You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2014/09/24 15:01:37 UTC

git commit: Refactoring of the install-kar goal of the karaf-maven-plugin

Repository: karaf
Updated Branches:
  refs/heads/master 222fcbda0 -> 2f3fc9a45


Refactoring of the install-kar goal of the karaf-maven-plugin


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/2f3fc9a4
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/2f3fc9a4
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/2f3fc9a4

Branch: refs/heads/master
Commit: 2f3fc9a45ddf8b6e7f5f228544284365ea7ff545
Parents: 222fcbd
Author: Jean-Baptiste Onofré <jb...@apache.org>
Authored: Wed Sep 24 15:01:14 2014 +0200
Committer: Jean-Baptiste Onofré <jb...@apache.org>
Committed: Wed Sep 24 15:01:14 2014 +0200

----------------------------------------------------------------------
 .../main/resources/archetype-resources/pom.xml  |  19 +-
 .../karaf/tooling/features/InstallKarsMojo.java | 523 +++++++++----------
 2 files changed, 267 insertions(+), 275 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/2f3fc9a4/archetypes/assembly/src/main/resources/archetype-resources/pom.xml
----------------------------------------------------------------------
diff --git a/archetypes/assembly/src/main/resources/archetype-resources/pom.xml b/archetypes/assembly/src/main/resources/archetype-resources/pom.xml
index 83628c4..a3b1d7c 100644
--- a/archetypes/assembly/src/main/resources/archetype-resources/pom.xml
+++ b/archetypes/assembly/src/main/resources/archetype-resources/pom.xml
@@ -88,12 +88,25 @@
                 <groupId>org.apache.karaf.tooling</groupId>
                 <artifactId>karaf-maven-plugin</artifactId>
                 <configuration>
-                    <startupFeatures></startupFeatures>
+                    <installedFeatures>
+                        <feature>wrapper</feature>
+                    </installedFeatures>
                     <bootFeatures>
-                        <feature>standard</feature>
+                        <feature>jaas</feature>
+                        <feature>shell</feature>
+                        <feature>ssh</feature>
                         <feature>management</feature>
+                        <feature>bundle</feature>
+                        <feature>config</feature>
+                        <feature>deployer</feature>
+                        <feature>diagnostic</feature>
+                        <feature>instance</feature>
+                        <feature>kar</feature>
+                        <feature>log</feature>
+                        <feature>package</feature>
+                        <feature>service</feature>
+                        <feature>system</feature>
                     </bootFeatures>
-                    <installedFeatures></installedFeatures>
                 </configuration>
             </plugin>
         </plugins>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2f3fc9a4/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
index ef06c6d..5bc41d6 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
@@ -25,33 +25,15 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-
-import javax.xml.bind.JAXBException;
-import javax.xml.stream.XMLStreamException;
+import java.util.*;
 
 import org.apache.felix.utils.properties.Properties;
 import org.apache.karaf.features.BundleInfo;
 import org.apache.karaf.features.Dependency;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.internal.model.Bundle;
-import org.apache.karaf.features.internal.model.Conditional;
-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.features.internal.model.*;
 import org.apache.karaf.kar.internal.Kar;
 import org.apache.karaf.tooling.utils.MojoSupport;
 import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 
@@ -98,12 +80,6 @@ public class InstallKarsMojo extends MojoSupport {
     protected int defaultStartLevel = 30;
 
     /**
-     * if false, unpack to system and add bundles to startup.properties
-     * if true, unpack to system and add feature to features config
-     */
-    protected boolean dontAddToStartup;
-
-    /**
      * Directory used during build to construction the Karaf system repository.
      *
      * @parameter default-value="${project.build.directory}/assembly/system"
@@ -133,33 +109,33 @@ public class InstallKarsMojo extends MojoSupport {
     private List<String> installedFeatures;
 
     /**
-     * When a feature depends on another feature, try to find it in another referenced feature-file and install that one
-     * too.
+     * Ignore the dependency attribute (dependency="[true|false]") on bundle
      *
      * @parameter
      */
-    private boolean addTransitiveFeatures = true;
+    protected boolean ignoreDependencyFlag = true;
 
     private URI system;
     private Properties startupProperties = new Properties();
-    private Set<Feature> featureSet = new HashSet<Feature>();
-    private List<Dependency> missingDependencies = new ArrayList<Dependency>();
 
     // an access layer for available Aether implementation
     protected DependencyHelper dependencyHelper;
 
-    /**
-     * list of features to  install into local repo.
-     */
-    private List<Feature> localRepoFeatures = new ArrayList<Feature>();
+    private static final String FEATURES_REPOSITORIES = "featuresRepositories";
+    private static final String FEATURES_BOOT = "featuresBoot";
 
     @SuppressWarnings("deprecation")
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
         this.dependencyHelper = DependencyHelperFactory.createDependencyHelper(this.container, this.project, this.mavenSession, getLog());
+
+        // creating system directory
+        getLog().info("Creating system directory");
         systemDirectory.mkdirs();
         system = systemDirectory.toURI();
+
         if (startupPropertiesFile.exists()) {
+            getLog().info("Loading startup.properties");
             try {
                 InputStream in = new FileInputStream(startupPropertiesFile);
                 try {
@@ -171,126 +147,154 @@ public class InstallKarsMojo extends MojoSupport {
                 throw new MojoFailureException("Could not open existing startup.properties file at " + startupPropertiesFile, e);
             }
         } else {
+            getLog().info("Creating startup.properties");
             startupProperties.setHeader(Collections.singletonList("#Bundles to be started on startup, with startlevel"));
             if (!startupPropertiesFile.getParentFile().exists()) {
                 startupPropertiesFile.getParentFile().mkdirs();
             }
         }
 
-        OfflineFeaturesService featuresService = new OfflineFeaturesService();
+        Set<String> repositories = new HashSet<String>();
+        Map<Feature, Boolean> features = new HashMap<Feature, Boolean>();
 
+        // loading kar and featres repositories
+        getLog().info("Loading kar and features repositories dependencies with compile or runtime scopes");
+        getLog().info("The startup.properties file is updated using kar and features dependency with a scope different from runtime, or defined in the <startupFeatures/> plugin configuration");
         Collection<Artifact> dependencies = project.getDependencyArtifacts();
-        StringBuilder buf = new StringBuilder();
         for (Artifact artifact : dependencies) {
-            dontAddToStartup = "runtime".equals(artifact.getScope());
-            if ("kar".equals(artifact.getType()) && acceptScope(artifact)) {
-                File file = artifact.getFile();
-                try {
-                    Kar kar = new Kar(file.toURI());
-                    kar.extract(new File(system.getPath()), new File(workDirectory));
-                    for (URI repoUri : kar.getFeatureRepos()) {
-                        featuresService.addRepository(repoUri);
-                    }
-                } catch (Exception e) {
-                    throw new RuntimeException("Could not install kar: " + artifact.toString() + "\n", e);
-                    //buf.append("Could not install kar: ").append(artifact.toString()).append("\n");
-                    //buf.append(e.getMessage()).append("\n\n");
-                }
-            }
-            if ("features".equals(artifact.getClassifier()) && acceptScope(artifact)) {
-                String uri = this.dependencyHelper.artifactToMvn(artifact);
-
-                File source = artifact.getFile();
-                DefaultRepositoryLayout layout = new DefaultRepositoryLayout();
-
-                //remove timestamp version
-                artifact = factory.createArtifactWithClassifier(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), artifact.getType(), artifact.getClassifier());
-                File target = new File(system.resolve(layout.pathOf(artifact)));
-
-                if (!target.exists()) {
-                    target.getParentFile().mkdirs();
+            boolean addToStartup = !artifact.getScope().equals("runtime");
+            if (artifact.getScope().equals("compile") || artifact.getScope().equals("runtime")) {
+                if (artifact.getType().equals("kar")) {
+                    File karFile = artifact.getFile();
+                    getLog().info("Extracting " + artifact.toString() + " kar");
                     try {
-                        copy(source, target);
-                    } catch (RuntimeException e) {
-                        getLog().error("Could not copy features " + uri + " from source file " + source, e);
+                        Kar kar = new Kar(karFile.toURI());
+                        kar.extract(new File(system.getPath()), new File(workDirectory));
+                        for (URI repositoryUri : kar.getFeatureRepos()) {
+                            resolveRepository(repositoryUri.getPath(), repositories, features, false, addToStartup);
+                        }
+                    } catch (Exception e) {
+                        throw new RuntimeException("Can not install " + artifact.toString() + " kar", e);
                     }
-
-                    // for snapshot, generate the repository metadata in order to avoid override of snapshot from remote repositories
-                    if (artifact.isSnapshot()) {
-                        getLog().debug("Feature " + uri + " is a SNAPSHOT, generate the maven-metadata-local.xml file");
-                        File metadataTarget = new File(target.getParentFile(), "maven-metadata-local.xml");
+                } else {
+                    if (artifact.getClassifier() != null && artifact.getClassifier().equals("features")) {
+                        getLog().info("Resolving " + artifact.toString() + " features repository");
+                        String repositoryUri = dependencyHelper.artifactToMvn(artifact);
                         try {
-                            MavenUtil.generateMavenMetadata(artifact, metadataTarget);
+                            resolveRepository(repositoryUri, repositories, features, true, addToStartup);
                         } catch (Exception e) {
-                            getLog().warn("Could not create maven-metadata-local.xml", e);
-                            getLog().warn("It means that this SNAPSHOT could be overwritten by an older one present on remote repositories");
+                            throw new MojoFailureException("Can not install " + artifact.toString() + " features repository", e);
                         }
                     }
-
-                }
-                try {
-                    featuresService.addRepository(URI.create(uri));
-                } catch (Exception e) {
-                    buf.append("Could not install feature: ").append(artifact.toString()).append("\n");
-                    buf.append(e.getMessage()).append("\n\n");
                 }
             }
         }
 
-        // install bundles listed in startup properties that weren't in kars into the system dir
-        Set<?> keySet = startupProperties.keySet();
-        for (Object keyObject : keySet) {
-            String key = (String) keyObject;
-            String path = this.dependencyHelper.pathFromMaven(key);
-            File target = new File(system.resolve(path));
-            if (!target.exists()) {
-                install(key, target);
+        // checking if all startup, installed, and boot features have been resolved
+        getLog().info("Checking features resolution");
+        List<String> resolvedFeaturesNames = new ArrayList<String>();
+        for (Feature feature : features.keySet()) {
+            resolvedFeaturesNames.add(feature.getName());
+        }
+        if (startupFeatures != null) {
+            for (String startupFeature : startupFeatures) {
+                if (!resolvedFeaturesNames.contains(startupFeature)) {
+                    throw new MojoFailureException("Feature " + startupFeature + " is not resolved. Check that <dependencies/> provide the kar of features repository providing this feature (with compile or runtime scope)");
+                }
             }
         }
-
-        // install bundles listed in install features not in system
-        for (Feature feature : localRepoFeatures) {
-            List<Bundle> bundles = new ArrayList<Bundle>();
-            bundles.addAll(feature.getBundle());
-            for (Conditional cond : feature.getConditional()) {
-                bundles.addAll(cond.getBundle());
+        if (bootFeatures != null) {
+            for (String bootFeature : bootFeatures) {
+                if (!resolvedFeaturesNames.contains(bootFeature)) {
+                    throw new MojoFailureException("Feature " + bootFeature + " is not resolved. Check that <dependencies/> provide the kar of features repository providing this feature (with compile or runtime scope)");
+                }
             }
-            for (Bundle bundle : bundles) {
-                String key = bundle.getLocation();
-                // remove wrap: protocol to resolve from maven
-                if (key.startsWith("wrap:")) {
-                    key = key.substring(5);
+        }
+        if (installedFeatures != null) {
+            for (String installedFeature : installedFeatures) {
+                if (!resolvedFeaturesNames.contains(installedFeature)) {
+                    throw new MojoFailureException("Feature " + installedFeature + " is not resolved. Check that <dependencies/> provide the kar of features repository providing this feature (with compile or runtime scope)");
                 }
-                String path = this.dependencyHelper.pathFromMaven(key);
-                File test = new File(system.resolve(path));
-                if (!test.exists()) {
-                    File target = new File(system.resolve(path));
-                    if (!target.exists()) {
-                        install(key, target);
-                        Artifact artifact = this.dependencyHelper.mvnToArtifact(key);
-                        if (artifact.isSnapshot()) {
-                            // generate maven-metadata-local.xml for the artifact
-                            File metadataSource = new File(this.dependencyHelper.resolveById(key, getLog()).getParentFile(), "maven-metadata-local.xml");
-                            File metadataTarget = new File(target.getParentFile(), "maven-metadata-local.xml");
-                            metadataTarget.getParentFile().mkdirs();
-                            try {
-                                if (!metadataSource.exists()) {
-                                    // the maven-metadata-local.xml doesn't exist in the local repo, generate one
-                                    MavenUtil.generateMavenMetadata(artifact, metadataTarget);
-                                } else {
-                                    // copy the metadata to the target
-                                    copy(metadataSource, metadataTarget);
-                                }
-                            } catch (IOException ioException) {
-                                getLog().warn(ioException);
-                                getLog().warn("Unable to copy the maven-metadata-local.xml, it means that this SNAPSHOT will be overwritten by a remote one (if exist)");
+            }
+        }
+
+        // install features/bundles
+        getLog().info("Installing features");
+        for (Feature feature : features.keySet()) {
+            try {
+                if (features.get(feature) || (startupFeatures != null && startupFeatures.contains(feature.getName()))) {
+                    // the feature is a startup feature, updating startup.properties file
+                    getLog().info("Feature " + feature.getName() + " is defined as a startup feature");
+                    getLog().info("= Updating startup.properties file");
+                    List<String> comment = Arrays.asList(new String[]{"", "# feature: " + feature.getName() + " version: " + feature.getVersion()});
+                    for (BundleInfo bundleInfo : feature.getBundles()) {
+                        String bundleLocation = bundleInfo.getLocation();
+                        String bundleStartLevel = Integer.toString(bundleInfo.getStartLevel() == 0 ? defaultStartLevel : bundleInfo.getStartLevel());
+                        if (startupProperties.containsKey(bundleLocation)) {
+                            int oldStartLevel = Integer.decode((String) startupProperties.get(bundleLocation));
+                            if (oldStartLevel > bundleInfo.getStartLevel()) {
+                                startupProperties.put(bundleLocation, bundleStartLevel);
                             }
+                        } else {
+                            if (comment == null) {
+                                startupProperties.put(bundleLocation, bundleStartLevel);
+                            } else {
+                                startupProperties.put(bundleLocation, comment, bundleStartLevel);
+                                comment = null;
+                            }
+                        }
+                    }
+                    // add the feature in the system folder
+                    resolveFeature(feature, features);
+                } else if (bootFeatures != null && bootFeatures.contains(feature.getName())) {
+                    // the feature is a boot feature, updating the etc/org.apache.karaf.features.cfg file
+                    getLog().info("Feature " + feature.getName() + " is defined as a boot feature");
+                    if (featuresCfgFile.exists()) {
+                        getLog().info("= Updating " + featuresCfgFile.getPath());
+                        Properties featuresProperties = new Properties();
+                        InputStream in = new FileInputStream(featuresCfgFile);
+                        try {
+                            featuresProperties.load(in);
+                        } finally {
+                            in.close();
+                        }
+                        String featuresBoot = featuresProperties.getProperty(FEATURES_BOOT);
+                        featuresBoot = featuresBoot != null && featuresBoot.length() > 0 ? featuresBoot + "," : "";
+                        if (!featuresBoot.contains(feature.getName())) {
+                            featuresBoot = featuresBoot + feature.getName();
+                            featuresProperties.put(FEATURES_BOOT, featuresBoot);
+                            featuresProperties.save(featuresCfgFile);
                         }
                     }
+                    // add the feature in the system folder
+                    resolveFeature(feature, features);
+                } else if (installedFeatures != null && installedFeatures.contains(feature.getName())) {
+                    getLog().info("Feature " + feature.getName() + " is defined as a installed feature");
+                    // add the feature in the system folder
+                    resolveFeature(feature, features);
+                } else {
+                    getLog().debug("Feature " + feature.getName() + " is not installed");
                 }
+            } catch (Exception e) {
+                throw new MojoFailureException("Can not install " + feature.getName() + " feature", e);
             }
         }
 
+        // install bundles defined in startup.properties
+        getLog().info("Installing bundles defined in startup.properties in the system");
+        Set<?> startupBundles = startupProperties.keySet();
+        for (Object startupBundle : startupBundles) {
+            String bundlePath = this.dependencyHelper.pathFromMaven((String) startupBundle);
+            File bundleFile = new File(system.resolve(bundlePath));
+            if (!bundleFile.exists()) {
+                File bundleSource = this.dependencyHelper.resolveById((String) startupBundle, getLog());
+                bundleFile.getParentFile().mkdirs();
+                copy(bundleSource, bundleFile);
+            }
+        }
+
+        // generate the startup.properties file
+        getLog().info("Generating the startup.properties file");
         try {
             OutputStream out = new FileOutputStream(startupPropertiesFile);
             try {
@@ -299,183 +303,158 @@ public class InstallKarsMojo extends MojoSupport {
                 out.close();
             }
         } catch (IOException e) {
-            throw new MojoFailureException("Could not write startup.properties file at " + startupPropertiesFile, e);
+            throw new MojoFailureException("Can not write " + startupPropertiesFile, e);
         }
-        if (buf.length() > 0) {
-            throw new MojoExecutionException("Could not unpack all dependencies:\n" + buf.toString());
-        }
-    }
-
-    private void install(String key, File target) throws MojoFailureException {
-        File source = this.dependencyHelper.resolveById(key, getLog());
-        target.getParentFile().mkdirs();
-        copy(source, target);
     }
 
-    private boolean acceptScope(Artifact artifact) {
-        return "compile".equals(artifact.getScope()) || "runtime".equals(artifact.getScope());
-    }
-
-    private class OfflineFeaturesService {
-        private static final String FEATURES_REPOSITORIES = "featuresRepositories";
-        private static final String FEATURES_BOOT = "featuresBoot";
-
-        public void addRepository(URI uri) throws Exception {
-            if (dontAddToStartup) {
-                getLog().info("Adding feature repository to system: " + uri);
-                if (featuresCfgFile.exists()) {
-                    Properties properties = new Properties();
-                    InputStream in = new FileInputStream(featuresCfgFile);
-                    try {
-                        properties.load(in);
-                    } finally {
-                        in.close();
-                    }
-                    String existingFeatureRepos = retrieveProperty(properties, FEATURES_REPOSITORIES);
-                    if (!existingFeatureRepos.contains(uri.toString())) {
-                        existingFeatureRepos = existingFeatureRepos + uri.toString();
-                        properties.put(FEATURES_REPOSITORIES, existingFeatureRepos);
-                    }
-                    Features repo = loadAndCopyRepo(uri);
-                    for (Feature feature : repo.getFeature()) {
-                        featureSet.add(feature);
-                        if (startupFeatures != null && startupFeatures.contains(feature.getName())) {
-                            installFeature(feature);
-                        } else if (bootFeatures != null && bootFeatures.contains(feature.getName())) {
-                            localRepoFeatures.add(feature);
-                            missingDependencies.addAll(feature.getDependencies());
-                            String existingBootFeatures = retrieveProperty(properties, FEATURES_BOOT);
-                            if (!existingBootFeatures.contains(feature.getName())) {
-                                existingBootFeatures = existingBootFeatures + feature.getName();
-                                properties.put(FEATURES_BOOT, existingBootFeatures);
-                            }
-                        } else if (installedFeatures != null && installedFeatures.contains(feature.getName())) {
-                            localRepoFeatures.add(feature);
-                            missingDependencies.addAll(feature.getDependencies());
-                        }
-                    }
-                    if (addTransitiveFeatures) {
-                        addMissingDependenciesToRepo();
-                    }
-                    FileOutputStream out = new FileOutputStream(featuresCfgFile);
-                    try {
-                        properties.save(out);
-                    } finally {
-                        out.close();
-                    }
-                }
-            } else {
-                getLog().info("Installing feature " + uri + " to system and startup.properties");
-                Features features = readFeatures(uri);
-                for (Feature feature : features.getFeature()) {
-                    installFeature(feature);
-                }
+    private void resolveRepository(String repository, Set<String> repositories, Map<Feature, Boolean> features, boolean updateFeaturesCfgFile, boolean updateStartupProperties) throws Exception {
+        // check if the repository has not been processed
+        if (repositories.contains(repository)) {
+            return;
+        }
+        getLog().info("Resolving " + repository + " features repository");
+        repositories.add(repository);
+        // update etc/org.apache.karaf.features.cfg file
+        if (updateFeaturesCfgFile && featuresCfgFile.exists()) {
+            Properties featuresProperties = new Properties();
+            InputStream in = new FileInputStream(featuresCfgFile);
+            try {
+                featuresProperties.load(in);
+            } finally {
+                in.close();
+            }
+            String featureRepos = featuresProperties.getProperty(FEATURES_REPOSITORIES);
+            featureRepos = featureRepos != null && featureRepos.length() > 0 ? featureRepos + "," : "";
+            if (!featureRepos.contains(repository)) {
+                featureRepos = featureRepos + repository;
+                featuresProperties.put(FEATURES_REPOSITORIES, featureRepos);
+                featuresProperties.save(featuresCfgFile);
             }
         }
-
-        private Features loadAndCopyRepo(URI uri) throws MojoExecutionException, MojoFailureException, JAXBException, XMLStreamException, IOException {
-            String repositoryPath = dependencyHelper.pathFromMaven(uri.toASCIIString());
-            getLog().info("Copying repo " + uri);
-            File repositoryTargetInSystemRepository = new File(system.resolve(repositoryPath));
-            if (!repositoryTargetInSystemRepository.exists()) {
-                File innerRepositorySourceFile = dependencyHelper.resolveById(uri.toASCIIString(), getLog());
-                repositoryTargetInSystemRepository.getParentFile().mkdirs();
-                copy(innerRepositorySourceFile, repositoryTargetInSystemRepository);
-
-                // add metadata for snapshot
-                Artifact innerRepositoryArtifact = dependencyHelper.mvnToArtifact(uri.toASCIIString());
-                if (innerRepositoryArtifact.isSnapshot()) {
-                    getLog().debug("Feature repository " + uri + " is a SNAPSHOT, generate the maven-metadata-local.xml file");
-                    File metadataTarget = new File(repositoryTargetInSystemRepository.getParentFile(), "maven-metadata-local.xml");
+        // resolving repository location
+        File repositoryFile;
+        if (repository.startsWith("mvn")) {
+            repositoryFile = dependencyHelper.resolveById(repository, getLog());
+            repository = dependencyHelper.pathFromMaven(repository);
+        } else {
+            repositoryFile = new File(repository);
+        }
+        // copy the repository file in system folder
+        File repositoryFileInSystemFolder = new File(system.resolve(repository));
+        if (!repositoryFileInSystemFolder.exists()) {
+            repositoryFileInSystemFolder.getParentFile().mkdirs();
+            copy(repositoryFile, repositoryFileInSystemFolder);
+            // add metadata for snapshot
+            if (repository.startsWith("mvn")) {
+                Artifact repositoryArtifact = dependencyHelper.mvnToArtifact(repository);
+                if (repositoryArtifact.isSnapshot()) {
+                    File metadataTarget = new File(repositoryFileInSystemFolder.getParentFile(), "maven-metadata-local.xml");
                     try {
-                        MavenUtil.generateMavenMetadata(innerRepositoryArtifact, metadataTarget);
+                        MavenUtil.generateMavenMetadata(repositoryArtifact, metadataTarget);
                     } catch (Exception e) {
                         getLog().warn("Could not create maven-metadata-local.xml", e);
                         getLog().warn("It means that this SNAPSHOT could be overwritten by an older one present on remote repositories");
                     }
                 }
             }
-            Features features = readFeatures(repositoryTargetInSystemRepository.toURI());
-            for (String innerRepository : features.getRepository()) {
-                loadAndCopyRepo(URI.create(innerRepository));
-            }
-            return features;
         }
-
-        private void addMissingDependenciesToRepo() {
-            for (ListIterator<Dependency> iterator = missingDependencies.listIterator(); iterator.hasNext(); ) {
-                Dependency dependency = iterator.next();
-                Feature depFeature = lookupFeature(dependency);
-                if (depFeature == null) {
-                    continue;
-                }
-                localRepoFeatures.add(depFeature);
-                iterator.remove();
-                addAllMissingDependencies(iterator, depFeature);
-            }
+        // loading the model
+        Features featuresModel = JaxbUtil.unmarshal(repositoryFile.toURI().toString(), new FileInputStream(repositoryFile), false);
+        // recursively process the inner repositories
+        for (String innerRepository : featuresModel.getRepository()) {
+            resolveRepository(innerRepository, repositories, features, false, updateStartupProperties);
+        }
+        // update features
+        for (Feature feature : featuresModel.getFeature()) {
+            features.put(feature, updateStartupProperties);
         }
+    }
 
-        private void addAllMissingDependencies(ListIterator<Dependency> iterator, Feature depFeature) {
-            for (Dependency dependency : depFeature.getDependencies()) {
-                if (!missingDependencies.contains(dependency)) {
-                    iterator.add(dependency);
+    private void resolveFeature(Feature feature, Map<Feature, Boolean> features) throws Exception {
+        for (Dependency dependency : feature.getFeature()) {
+            for (Feature f : features.keySet()) {
+                if (f.getName().equals(dependency.getName())) {
+                    resolveFeature(f, features);
                 }
             }
         }
 
-        private String retrieveProperty(Properties properties, String key) {
-            String val = properties.getProperty(key);
-            return val != null && val.length() > 0 ? val + "," : "";
-        }
+        getLog().info("Resolving feature " + feature.getName());
 
-        private Features readFeatures(URI uri) throws MojoExecutionException, XMLStreamException, JAXBException, IOException {
-            File repoFile;
-            if (uri.toString().startsWith("mvn:")) {
-                URI featuresPath = system.resolve(dependencyHelper.pathFromMaven(uri.toString()));
-                repoFile = new File(featuresPath);
+        // installing feature bundles
+        getLog().info("= Installing bundles from " + feature.getName() + " feature");
+        for (Bundle bundle : feature.getBundle()) {
+            if (!ignoreDependencyFlag && bundle.isDependency()) {
+                getLog().warn("== Bundle " + bundle.getLocation() + " is defined as dependency, so it's not installed");
             } else {
-                repoFile = new File(uri);
-            }
-            return JaxbUtil.unmarshal(repoFile.toURI().toASCIIString(), false);
-        }
-
-        public void installFeature(org.apache.karaf.features.Feature feature) throws Exception {
-            List<String> comment = Arrays.asList(new String[]{"", "# feature: " + feature.getName() + " version: " + feature.getVersion()});
-            for (BundleInfo bundle : feature.getBundles()) {
-                String location = bundle.getLocation();
-                String startLevel = Integer.toString(bundle.getStartLevel() == 0 ? defaultStartLevel : bundle.getStartLevel());
-                if (startupProperties.containsKey(location)) {
-                    int oldStartLevel = Integer.decode((String) startupProperties.get(location));
-                    if (oldStartLevel > bundle.getStartLevel()) {
-                        startupProperties.put(location, startLevel);
-                    }
+                getLog().info("== Installing bundle " + bundle.getLocation());
+                String bundleLocation = bundle.getLocation();
+                // cleanup prefixes
+                if (bundleLocation.startsWith("wrap:")) {
+                    bundleLocation = bundleLocation.substring("wrap:".length());
+                }
+                if (bundleLocation.startsWith("blueprint:")) {
+                    bundleLocation = bundleLocation.substring("blueprint:".length());
+                }
+                if (bundleLocation.startsWith("webbundle:")) {
+                    bundleLocation = bundleLocation.substring("webbundle:".length());
+                }
+                if (bundleLocation.startsWith("war:")) {
+                    bundleLocation = bundleLocation.substring("war:".length());
+                }
+                File bundleFile;
+                if (bundleLocation.startsWith("mvn:")) {
+                    bundleFile = dependencyHelper.resolveById(bundleLocation, getLog());
+                    bundleLocation = dependencyHelper.pathFromMaven(bundleLocation);
                 } else {
-                    if (comment == null) {
-                        startupProperties.put(location, startLevel);
-                    } else {
-                        startupProperties.put(location, comment, startLevel);
-                        comment = null;
+                    bundleFile = new File(new URI(bundleLocation));
+                }
+                File bundleSystemFile = new File(system.resolve(bundleLocation));
+                copy(bundleFile, bundleSystemFile);
+                // add metadata for snapshot
+                if (bundleLocation.startsWith("mvn")) {
+                    Artifact bundleArtifact = dependencyHelper.mvnToArtifact(bundleLocation);
+                    if (bundleArtifact.isSnapshot()) {
+                        File metadataTarget = new File(bundleSystemFile.getParentFile(), "maven-metadata-local.xml");
+                        try {
+                            MavenUtil.generateMavenMetadata(bundleArtifact, metadataTarget);
+                        } catch (Exception e) {
+                            getLog().warn("Could not create maven-metadata-local.xml", e);
+                            getLog().warn("It means that this SNAPSHOT could be overwritten by an older one present on remote repositories");
+                        }
                     }
                 }
             }
         }
 
-        private Feature lookupFeature(Dependency dependency) {
-            for (Feature feature : featureSet) {
-                if (featureSatisfiesDependency(feature, dependency)) {
-                    return feature;
-                }
+        // installing feature config files
+        getLog().info("= Installing configuration files from " + feature.getName() + " feature");
+        for (ConfigFile configFile : feature.getConfigfile()) {
+            getLog().warn("== Installing configuration file " + configFile.getLocation());
+            String configFileLocation = configFile.getLocation();
+            File configFileFile;
+            if (configFileLocation.startsWith("mvn:")) {
+                configFileFile = dependencyHelper.resolveById(configFileLocation, getLog());
+                configFileLocation = dependencyHelper.pathFromMaven(configFileLocation);
+            } else {
+                configFileFile = new File(new URI(configFileLocation));
             }
-            return null;
-        }
-
-        private boolean featureSatisfiesDependency(Feature feature, Dependency dependency) {
-            if (!feature.getName().equals(dependency.getName())) {
-                return false;
+            File configFileSystemFile = new File(system.resolve(configFileLocation));
+            copy(configFileFile, configFileSystemFile);
+            // add metadata for snapshot
+            if (configFileLocation.startsWith("mvn")) {
+                Artifact configFileArtifact = dependencyHelper.mvnToArtifact(configFileLocation);
+                if (configFileArtifact.isSnapshot()) {
+                    File metadataTarget = new File(configFileSystemFile.getParentFile(), "maven-metadata-local.xml");
+                    try {
+                        MavenUtil.generateMavenMetadata(configFileArtifact, metadataTarget);
+                    } catch (Exception e) {
+                        getLog().warn("Could not create maven-metadata-local.xml", e);
+                        getLog().warn("It means that this SNAPSHOT could be overwritten by an older one present on remote repositories");
+                    }
+                }
             }
-            return true;
         }
-
     }
 
 }