--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>odlparent</artifactId>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <version>1.5.0-SNAPSHOT</version>
+ <relativePath>../odlparent/</relativePath>
+ </parent>
+ <artifactId>karaf-plugin</artifactId>
+ <packaging>maven-plugin</packaging>
+
+ <name>karaf-plugin Maven Plugin</name>
+
+ <!-- FIXME change it to the project's website -->
+ <url>http://maven.apache.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>3.0.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>${url.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.features</groupId>
+ <artifactId>org.apache.karaf.features.core</artifactId>
+ <version>${karaf.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <version>${karaf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <version>3.2</version>
+ <configuration>
+ <goalPrefix>karaf-plugin</goalPrefix>
+ <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+ </configuration>
+ <executions>
+ <execution>
+ <id>mojo-descriptor</id>
+ <goals>
+ <goal>descriptor</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>help-goal</id>
+ <goals>
+ <goal>helpmojo</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>run-its</id>
+ <build>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.7</version>
+ <configuration>
+ <debug>true</debug>
+ <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <postBuildHookScript>verify</postBuildHookScript>
+ <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+ <settingsFile>src/it/settings.xml</settingsFile>
+ <goals>
+ <goal>clean</goal>
+ <goal>test-compile</goal>
+ </goals>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>install</goal>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+
+ </build>
+ </profile>
+ </profiles>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<settings>
+ <profiles>
+ <profile>
+ <id>it-repo</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <repositories>
+ <repository>
+ <id>local.central</id>
+ <url>@localRepositoryUrl@</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>local.central</id>
+ <url>@localRepositoryUrl@</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+ </profile>
+ </profiles>
+</settings>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.opendaylight.odlparent.it</groupId>
+ <artifactId>simple-it</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <description>A simple IT verifying the basic use case.</description>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>@project.groupId@</groupId>
+ <artifactId>@project.artifactId@</artifactId>
+ <version>@project.version@</version>
+ <executions>
+ <execution>
+ <id>touch</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>touch</goal>
+ </goals>
+ <configuration>
+ <featureRepos>
+ <param>foo</param>
+ </featureRepos>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+File touchFile = new File( basedir, "target/touch.txt" );
+
+assert touchFile.isFile()
--- /dev/null
+package org.opendaylight.odlparent;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.DependencyFilter;
+import org.eclipse.aether.installation.InstallRequest;
+import org.eclipse.aether.installation.InstallationException;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.LocalRepositoryManager;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.DependencyRequest;
+import org.eclipse.aether.resolution.DependencyResolutionException;
+import org.eclipse.aether.resolution.DependencyResult;
+
+public class AetherUtil {
+
+ private RepositorySystem repoSystem;
+
+ private RepositorySystemSession repoSession;
+
+ private List<RemoteRepository> remoteRepos;
+
+ protected File localRepository;
+
+ public AetherUtil(RepositorySystem repoSystem,RepositorySystemSession repoSession,List<RemoteRepository> remoteRepos, File localRepository) {
+ this.repoSystem = repoSystem;
+ this.repoSession = repoSession;
+ this.remoteRepos = remoteRepos;
+ this.localRepository = localRepository;
+ }
+
+ public Set<Artifact> resolveDependencies(List<Dependency>dependencies,DependencyFilter filter) throws DependencyResolutionException {
+ Set<Artifact> artifacts = new LinkedHashSet<Artifact>();
+ CollectRequest collectRequest = new CollectRequest();
+ collectRequest.setDependencies(dependencies);
+ collectRequest.setRepositories(remoteRepos);
+ DependencyRequest request = new DependencyRequest(collectRequest,filter);
+ DependencyResult results = repoSystem.resolveDependencies(repoSession, request);
+ for(ArtifactResult artifactResult: results.getArtifactResults()) {
+ artifacts.add(artifactResult.getArtifact());
+ }
+ return artifacts;
+ }
+
+ public Artifact resolveArtifact(Artifact artifact) throws ArtifactResolutionException {
+ ArtifactRequest request = new ArtifactRequest(artifact, remoteRepos,null);
+ ArtifactResult result = repoSystem.resolveArtifact(repoSession, request);
+ return result.getArtifact();
+ }
+
+ public Artifact resolveArtifact(String coord) throws ArtifactResolutionException {
+ DefaultArtifact artifact = new DefaultArtifact(coord);
+ return resolveArtifact(artifact);
+ }
+
+ public Set<Artifact> resolveArtifacts(Set<String> coords) throws ArtifactResolutionException {
+ Set<Artifact> result = new LinkedHashSet<Artifact>();
+ for(String coord: coords) {
+ result.add(resolveArtifact(coord));
+ }
+ return result;
+ }
+
+ public Dependency toDependency(String coord) {
+ Artifact artifact = new DefaultArtifact(coord);
+ Dependency dependency = new Dependency(artifact, null);
+ return dependency;
+ }
+
+ public List<Dependency> toDependencies(List<String> coords) {
+ List<Dependency> result = new ArrayList<Dependency>();
+ for(String coord: coords) {
+ result.add(toDependency(coord));
+ }
+ return result;
+ }
+
+ public void installArtifacts(Set<Artifact> artifacts) throws InstallationException {
+ LocalRepository localRepo = new LocalRepository(localRepository);
+ LocalRepositoryManager localManager = repoSystem.newLocalRepositoryManager(repoSession, localRepo);
+ DefaultRepositorySystemSession localSession = new DefaultRepositorySystemSession();
+ localSession.setLocalRepositoryManager(localManager);
+ InstallRequest installRequest = new InstallRequest();
+ for(Artifact featureArtifact : artifacts) {
+ installRequest.addArtifact(featureArtifact);
+ }
+ repoSystem.install(localSession, installRequest);
+ }
+}
--- /dev/null
+package org.opendaylight.odlparent;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.karaf.features.internal.model.Bundle;
+import org.apache.karaf.features.internal.model.ConfigFile;
+import org.apache.karaf.features.internal.model.Feature;
+import org.apache.karaf.features.internal.model.Features;
+import org.apache.karaf.features.internal.model.JaxbUtil;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.ops4j.pax.url.mvn.Parser;
+
+public class FeatureUtil {
+
+ public static List<String> toCoord(List<URL> urls) throws MalformedURLException {
+ List<String> result = new ArrayList<String>();
+ for(URL url:urls) {
+ result.add(toCoord(url));
+ }
+ return result;
+ }
+
+ public static String toCoord(URL url) throws MalformedURLException {
+ String repository = url.toString();
+ String unwrappedRepo = repository.replaceFirst("wrap:", "");
+ Parser parser = new Parser(unwrappedRepo);
+ String coord = parser.getGroup().replace("mvn:","") + ":" + parser.getArtifact();
+ if(parser.getType() != null) {
+ coord = coord + ":" + parser.getType();
+ }
+ if(parser.getClassifier() != null) {
+ coord = coord + ":" + parser.getClassifier();
+ }
+ coord = coord + ":" + parser.getVersion().replaceAll("\\$.*$", "");
+ return coord;
+ }
+
+ public static Set<String> mvnUrlsToCoord(List<String> repository) throws MalformedURLException {
+ Set<String> result = new LinkedHashSet<String>();
+ for(String url:repository) {
+ result.add(toCoord(new URL(url)));
+ }
+ return result;
+ }
+
+ public static Set<String> featuresRepositoryToCoords(Features features) throws MalformedURLException {
+ return mvnUrlsToCoord(features.getRepository());
+ }
+
+ public static Set<String> featuresRepositoryToCoords(Set<Features> features) throws MalformedURLException {
+ Set<String> result = new LinkedHashSet<String>();
+ for(Features feature:features) {
+ result.addAll(featuresRepositoryToCoords(feature));
+ }
+ return result;
+ }
+
+ public static Set<String> featureToCoords(Feature feature) throws MalformedURLException {
+ Set<String> result = new LinkedHashSet<String>();
+ if(feature.getBundle() != null) {
+ result.addAll(bundlesToCoords(feature.getBundle()));
+ }
+ if(feature.getConfigfile() != null) {
+ result.addAll(configFilesToCoords(feature.getConfigfile()));
+ }
+ return result;
+ }
+
+ public static Set<String> configFilesToCoords(List<ConfigFile> configfiles) throws MalformedURLException {
+ Set<String> result = new LinkedHashSet<String>();
+ for(ConfigFile configFile: configfiles) {
+ result.add(toCoord(new URL(configFile.getLocation())));
+ }
+ return result;
+ }
+
+ public static Set<String> bundlesToCoords(List<Bundle> bundles) throws MalformedURLException {
+ Set<String> result = new LinkedHashSet<String>();
+ for(Bundle bundle: bundles) {
+ result.add(toCoord(new URL(bundle.getLocation())));
+ }
+ return result;
+ }
+
+ public static Set<String> featuresToCoords(Features features) throws MalformedURLException {
+ Set<String> result = new LinkedHashSet<String>();
+ if(features.getRepository() != null) {
+ result.addAll(featuresRepositoryToCoords(features));
+ }
+ if(features.getFeature() != null) {
+ for(Feature feature: features.getFeature() ) {
+ result.addAll(featureToCoords(feature));
+ }
+ }
+ return result;
+ }
+
+ public static Set<String> featuresToCoords(Set<Features> features) throws MalformedURLException {
+ Set<String> result = new LinkedHashSet<String>();
+ for(Features feature:features) {
+ result.addAll(featuresToCoords(feature));
+ }
+ return result;
+ }
+
+ public static LinkedHashSet<Features> readFeatures(Set<Artifact> featureArtifacts) throws FileNotFoundException {
+ LinkedHashSet<Features> result = new LinkedHashSet<Features>();
+ for(Artifact artifact: featureArtifacts) {
+ result.add(readFeature(artifact));
+ }
+ return result;
+ }
+
+ public static Features readFeature(Artifact artifact) throws FileNotFoundException {
+ Features result;
+ File file = artifact.getFile();
+ FileInputStream stream = new FileInputStream(file);
+ Features features = JaxbUtil.unmarshal(stream, false);
+ result = features;
+ return result;
+ }
+
+ public static Features readFeature(AetherUtil aetherUtil,String coords) throws ArtifactResolutionException, FileNotFoundException {
+ Artifact artifact = aetherUtil.resolveArtifact(coords);
+ return readFeature(artifact);
+ }
+
+ public static Set<Features> findAllFeaturesRecursively(AetherUtil aetherUtil,Features features,Set<String> existingCoords) throws MalformedURLException, FileNotFoundException, ArtifactResolutionException {
+ Set<Features> result = new LinkedHashSet<Features>();
+ Set<String> coords = FeatureUtil.featuresRepositoryToCoords(features);
+ for(String coord : coords) {
+ if(!existingCoords.contains(coord)) {
+ existingCoords.add(coord);
+ Features f = FeatureUtil.readFeature(aetherUtil,coord);
+ result.add(f);
+ result.addAll(findAllFeaturesRecursively(aetherUtil,FeatureUtil.readFeature(aetherUtil,coord), existingCoords));
+ }
+ }
+ return result;
+ }
+
+ public static Set<Features> findAllFeaturesRecursively(AetherUtil aetherUtil,Set<Features> features,Set<String> existingCoords) throws MalformedURLException, FileNotFoundException, ArtifactResolutionException {
+ Set<Features> result = new LinkedHashSet<Features>();
+ for(Features feature: features) {
+ result.addAll(findAllFeaturesRecursively(aetherUtil, feature, existingCoords));
+ }
+ return result;
+ }
+
+}
--- /dev/null
+package org.opendaylight.odlparent;
+
+import java.util.List;
+
+import org.eclipse.aether.graph.DependencyFilter;
+import org.eclipse.aether.graph.DependencyNode;
+
+public class KarafFeaturesDependencyFilter implements DependencyFilter {
+
+ public boolean accept(DependencyNode node, List<DependencyNode> parents) {
+ if(node != null
+ && node.getArtifact() != null
+ && node.getDependency() != null
+ && node.getDependency().getScope() != null
+ && node.getArtifact().getClassifier().equals("features")
+ && node.getArtifact().getExtension().equals("xml")) {
+ return true;
+ }
+ return false;
+ }
+
+}
--- /dev/null
+package org.opendaylight.odlparent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.artifact.DefaultArtifactType;
+import org.eclipse.aether.graph.Dependency;
+
+public class MvnToAetherMapper {
+
+ public static Dependency toAether(org.apache.maven.model.Dependency dependency) {
+ DefaultArtifact artifact = new DefaultArtifact(dependency.getGroupId(),
+ dependency.getArtifactId(),
+ dependency.getClassifier(),
+ null,
+ dependency.getVersion(),
+ new DefaultArtifactType(dependency.getType()));
+ Dependency result = new Dependency(artifact, null);
+ return result;
+ }
+
+ public static List<Dependency> toAether(List<org.apache.maven.model.Dependency> dependencies) {
+ List<Dependency> result = new ArrayList<Dependency>();
+ for(org.apache.maven.model.Dependency dependency : dependencies) {
+ result.add(toAether(dependency));
+ }
+ return result;
+ }
+}
--- /dev/null
+package org.opendaylight.odlparent;
+
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.karaf.features.internal.model.Bundle;
+import org.apache.karaf.features.internal.model.ConfigFile;
+import org.apache.karaf.features.internal.model.Feature;
+import org.apache.karaf.features.internal.model.Features;
+import org.apache.karaf.features.internal.model.JaxbUtil;
+import org.apache.karaf.tooling.url.CustomBundleURLStreamHandlerFactory;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.artifact.DefaultArtifactType;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.collection.DependencyCollectionException;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.installation.InstallRequest;
+import org.eclipse.aether.installation.InstallationException;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.LocalRepositoryManager;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.DependencyRequest;
+import org.eclipse.aether.resolution.DependencyResolutionException;
+import org.eclipse.aether.resolution.DependencyResult;
+import org.ops4j.pax.url.mvn.Parser;
+
+/**
+ * @goal populate-local-repo
+ * @phase prepare-package
+ */
+public class PopulateLocalRepoMojo
+ extends AbstractMojo {
+
+ static {
+ // Static initialization, as we may be invoked multiple times
+ URL.setURLStreamHandlerFactory(new CustomBundleURLStreamHandlerFactory());
+ }
+
+ /**
+ * @component
+ * @required
+ * @readonly
+ */
+ private MavenProject project;
+
+ /**
+ * The entry point to Aether, i.e. the component doing all the work.
+ *
+ * @component
+ */
+ private RepositorySystem repoSystem;
+
+ /**
+ * The current repository/network configuration of Maven.
+ *
+ * @parameter default-value="${repositorySystemSession}"
+ * @readonly
+ */
+ private RepositorySystemSession repoSession;
+
+ /**
+ * The project's remote repositories to use for the resolution of plugins and their dependencies.
+ *
+ * @parameter default-value="${project.remotePluginRepositories}"
+ * @readonly
+ */
+ private List<RemoteRepository> remoteRepos;
+
+ /**
+ * @parameter
+ */
+ private File localRepo;
+
+ private AetherUtil aetherUtil;
+
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ aetherUtil = new AetherUtil(repoSystem, repoSession, remoteRepos,localRepo);
+ try {
+ Set<Artifact> featureArtifacts = new LinkedHashSet<Artifact>();
+ featureArtifacts.addAll(aetherUtil.resolveDependencies(MvnToAetherMapper.toAether(project.getDependencies()),
+ new KarafFeaturesDependencyFilter()));
+ Set<Features> features = FeatureUtil.readFeatures(featureArtifacts);
+ features.addAll(FeatureUtil.findAllFeaturesRecursively(aetherUtil, features, FeatureUtil.featuresRepositoryToCoords(features)));
+ for(Features feature: features) {
+ getLog().info("Features Repos discovered recursively: " + feature.getName());
+ }
+ Set<Artifact> artifacts = aetherUtil.resolveArtifacts(FeatureUtil.featuresToCoords(features));
+ artifacts.addAll(featureArtifacts);
+
+ for(Artifact artifact: artifacts) {
+ getLog().info("Artifacts to be installed: " + artifact.toString());
+ }
+ if(localRepo != null) {
+ aetherUtil.installArtifacts(artifacts);
+ }
+ } catch (Exception e) {
+ throw new MojoExecutionException("Failure: ", e);
+ }
+ }
+}
<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v1.0 which accompanies this distribution,
and is available at http://www.eclipse.org/legal/epl-v10.html
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<module>features-parent</module>
<module>features-test</module>
<module>odlparent</module>
- </modules>
+ <module>karaf-plugin</module>
+ </modules>
<build>
<plugins>
</plugin>
</plugins>
</build>
-</project>
+</project>
\ No newline at end of file