http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/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 4306f17..bc238ab 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
@@ -19,24 +19,46 @@
 package org.apache.karaf.tooling.features;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.net.URI;
+import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.*;
-
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.apache.felix.utils.properties.InterpolationHelper;
 import org.apache.felix.utils.properties.Properties;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.ConfigFileInfo;
-import org.apache.karaf.features.ConfigInfo;
-import org.apache.karaf.features.Dependency;
-import org.apache.karaf.features.internal.model.*;
+import org.apache.karaf.features.internal.download.impl.DownloadManagerHelper;
+import org.apache.karaf.features.internal.model.Bundle;
+import org.apache.karaf.features.internal.model.Conditional;
+import org.apache.karaf.features.internal.model.Config;
+import org.apache.karaf.features.internal.model.ConfigFile;
+import org.apache.karaf.features.internal.model.Dependency;
+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.util.MapUtils;
 import org.apache.karaf.kar.internal.Kar;
+import org.apache.karaf.profile.Profile;
+import org.apache.karaf.profile.ProfileBuilder;
+import org.apache.karaf.profile.impl.Profiles;
+import org.apache.karaf.tooling.url.CustomBundleURLStreamHandlerFactory;
+import org.apache.karaf.tooling.utils.InternalMavenResolver;
+import org.apache.karaf.tooling.utils.IoUtils;
 import org.apache.karaf.tooling.utils.MojoSupport;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -45,6 +67,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.ops4j.pax.url.mvn.MavenResolver;
 
 /**
  * Installs kar dependencies into a server-under-construction in 
target/assembly
@@ -56,7 +79,7 @@ public class InstallKarsMojo extends MojoSupport {
      * Base directory used to copy the resources during the build (working 
directory).
      */
     @Parameter(defaultValue = "${project.build.directory}/assembly")
-    protected String workDirectory;
+    protected File workDirectory;
 
     /**
      * Features configuration file (etc/org.apache.karaf.features.cfg).
@@ -71,16 +94,23 @@ public class InstallKarsMojo extends MojoSupport {
     protected File startupPropertiesFile;
 
     /**
+     * Directory used during build to construction the Karaf system repository.
+     */
+    @Parameter(defaultValue="${project.build.directory}/assembly/system")
+    protected File systemDirectory;
+
+    /**
      * default start level for bundles in features that don't specify it.
      */
     @Parameter
     protected int defaultStartLevel = 30;
 
-    /**
-     * Directory used during build to construction the Karaf system repository.
-     */
-    @Parameter(defaultValue="${project.build.directory}/assembly/system")
-    protected File systemDirectory;
+    @Parameter
+    private List<String> startupRepositories;
+    @Parameter
+    private List<String> bootRepositories;
+    @Parameter
+    private List<String> installedRepositories;
 
     /**
      * List of features from runtime-scope features xml and kars to be 
installed into system and listed in startup.properties.
@@ -100,6 +130,25 @@ public class InstallKarsMojo extends MojoSupport {
     @Parameter
     private List<String> installedFeatures;
 
+    @Parameter
+    private List<String> startupBundles;
+    @Parameter
+    private List<String> bootBundles;
+    @Parameter
+    private List<String> installedBundles;
+    
+    @Parameter
+    private File profilesDirectory;
+
+    @Parameter
+    private List<String> bootProfiles;
+
+    @Parameter
+    private List<String> startupProfiles;
+
+    @Parameter
+    private List<String> installedProfiles;
+
     /**
      * Ignore the dependency attribute (dependency="[true|false]") on bundle
      */
@@ -118,8 +167,8 @@ public class InstallKarsMojo extends MojoSupport {
     @Parameter(defaultValue = "false")
     protected boolean useReferenceUrls;
 
-    private URI system;
-    private Properties startupProperties = new Properties();
+    @Parameter
+    protected boolean installAllFeaturesByDefault = true;
 
     // an access layer for available Aether implementation
     protected DependencyHelper dependencyHelper;
@@ -127,429 +176,569 @@ public class InstallKarsMojo extends MojoSupport {
     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());
+        MavenResolver resolver = new InternalMavenResolver(dependencyHelper, 
getLog());
+        CustomBundleURLStreamHandlerFactory.install(resolver);
+
+        try {
+            doExecute();
+        }
+        catch (MojoExecutionException | MojoFailureException e) {
+            throw e;
+        }
+        catch (Exception e) {
+            throw new MojoExecutionException("Unable to build assembly", e);
+        }
+        finally {
+            CustomBundleURLStreamHandlerFactory.uninstall();
+        }
+    }
+
+    protected void doExecute() throws Exception {
         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 {
-                    startupProperties.load(in);
-                } finally {
-                    in.close();
-                }
-            } catch (IOException e) {
-                throw new MojoFailureException("Could not open existing 
startup.properties file at " + startupPropertiesFile, e);
+        IoUtils.deleteRecursive(new File(systemDirectory, "generated"));
+
+        startupRepositories = nonNullList(startupRepositories);
+        bootRepositories = nonNullList(bootRepositories);
+        installedRepositories = nonNullList(installedRepositories);
+        startupBundles = nonNullList(startupBundles);
+        bootBundles = nonNullList(bootBundles);
+        installedBundles = nonNullList(installedBundles);
+        startupFeatures = nonNullList(startupFeatures);
+        bootFeatures = nonNullList(bootFeatures);
+        installedFeatures = nonNullList(installedFeatures);
+        startupProfiles = nonNullList(startupProfiles);
+        bootProfiles = nonNullList(bootProfiles);
+        installedProfiles = nonNullList(installedProfiles);
+
+        if (!startupProfiles.isEmpty() || !bootProfiles.isEmpty() || 
!installedProfiles.isEmpty()) {
+            if (profilesDirectory == null) {
+                throw new IllegalArgumentException("profilesDirectory must be 
specified");
             }
-        } 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();
-            }
-        }
-
-        Set<String> repositories = new HashSet<>();
-        Map<Feature, Boolean> features = new HashMap<>();
-
-        // loading kar and features 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();
-        for (Artifact artifact : dependencies) {
-            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 {
-                        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);
-                    }
-                } else {
-                    if (artifact.getClassifier() != null && 
artifact.getClassifier().equals("features")) {
-                        getLog().info("Resolving " + artifact.toString() + " 
features repository");
-                        String repositoryUri = 
dependencyHelper.artifactToMvn(artifact);
-                        try {
-                            resolveRepository(repositoryUri, repositories, 
features, true, addToStartup);
-                        } catch (Exception e) {
-                            throw new MojoFailureException("Can not install " 
+ artifact.toString() + " features repository", e);
+        }
+
+        if (featureRepositories != null && !featureRepositories.isEmpty()) {
+            getLog().warn("Use of featureRepositories is deprecated, use 
startupRepositories, bootRepositories or installedRepositories instead");
+            startupRepositories.addAll(featureRepositories);
+            bootRepositories.addAll(featureRepositories);
+            installedRepositories.addAll(featureRepositories);
+        }
+
+        // Build optional features and known prerequisites
+        Map<String, List<String>> prereqs = new HashMap<>();
+        prereqs.put("blueprint:", Arrays.asList("deployer", 
"aries-blueprint"));
+        prereqs.put("spring:", Arrays.asList("deployer", "spring"));
+        prereqs.put("wrap:", Arrays.asList("wrap"));
+        prereqs.put("war:", Arrays.asList("war"));
+
+
+        // Loading kars and features repositories
+        getLog().info("Loading kar and features repositories dependencies");
+        for (Artifact artifact : project.getDependencyArtifacts()) {
+            if ("kar".equals(artifact.getType())) {
+                File karFile = artifact.getFile();
+                getLog().info("Extracting " + artifact.toString() + " kar");
+                try {
+                    Kar kar = new Kar(karFile.toURI());
+                    kar.extract(systemDirectory, workDirectory);
+                    for (URI repositoryUri : kar.getFeatureRepos()) {
+                        switch (artifact.getScope()) {
+                        case "compile":
+                            startupRepositories.add(repositoryUri.getPath());
+                            break;
+                        case "runtime":
+                            bootRepositories.add(repositoryUri.getPath());
+                            break;
+                        case "provided":
+                            installedRepositories.add(repositoryUri.getPath());
+                            break;
                         }
                     }
+                } catch (Exception e) {
+                    throw new RuntimeException("Can not install " + 
artifact.toString() + " kar", e);
+                }
+            } else if ("features".equals(artifact.getClassifier())) {
+                String repositoryUri = 
dependencyHelper.artifactToMvn(artifact);
+                switch (artifact.getScope()) {
+                case "compile":
+                    startupRepositories.add(repositoryUri);
+                    break;
+                case "runtime":
+                    bootRepositories.add(repositoryUri);
+                    break;
+                case "provided":
+                    installedRepositories.add(repositoryUri);
+                    break;
+                }
+            } else if ("jar".equals(artifact.getType()) || 
"bundle".equals(artifact.getType())) {
+                String bundleUri = dependencyHelper.artifactToMvn(artifact);
+                switch (artifact.getScope()) {
+                case "compile":
+                    startupBundles.add(bundleUri);
+                    break;
+                case "runtime":
+                    bootBundles.add(bundleUri);
+                    break;
+                case "provided":
+                    installedBundles.add(bundleUri);
+                    break;
                 }
             }
         }
-        if (featureRepositories != null) {
-            for (String repositoryUri : featureRepositories) {
-                try {
-                    resolveRepository(repositoryUri, repositories, features, 
true, false);
-                } catch (Exception e) {
-                    throw new MojoFailureException("Can not install " + 
repositoryUri + " features repository", e);
-                }
+
+        // Load profiles
+        Map<String, Profile> allProfiles;
+        if (profilesDirectory != null) {
+            allProfiles = Profiles.loadProfiles(profilesDirectory.toPath());
+        } else {
+            allProfiles = new HashMap<>();
+        }
+        // Generate profiles
+        Profile startupProfile = generateProfile(allProfiles, startupProfiles, 
startupRepositories, startupFeatures, startupBundles);
+        Profile bootProfile = generateProfile(allProfiles, bootProfiles, 
bootRepositories, bootFeatures, bootBundles);
+        Profile installedProfile = generateProfile(allProfiles, 
installedProfiles, installedRepositories, installedFeatures, installedBundles);
+
+        //
+        // Compute overall profile
+        //
+        Profile overallProfile = 
ProfileBuilder.Factory.create(UUID.randomUUID().toString())
+                .setParents(Arrays.asList(startupProfile.getId(), 
bootProfile.getId(), installedProfile.getId()))
+                .getProfile();
+        Profile overallOverlay = Profiles.getOverlay(overallProfile, 
allProfiles);
+        Profile overallEffective = Profiles.getEffective(overallOverlay, 
false);
+
+        Hashtable<String, String> agentProps = new 
Hashtable<>(overallEffective.getConfiguration("org.ops4j.pax.url.mvn"));
+        final Map<String, String> properties = new HashMap<>();
+        properties.put("karaf.default.repository", "system");
+        InterpolationHelper.performSubstitution(agentProps, new 
InterpolationHelper.SubstitutionCallback() {
+            @Override
+            public String getValue(String key) {
+                return properties.get(key);
             }
+        }, false, false, true);
+
+        //
+        // Write all configuration files
+        //
+        for (Map.Entry<String, byte[]> config : 
overallEffective.getFileConfigurations().entrySet()) {
+            Path configFile = workDirectory.toPath().resolve("etc/" + 
config.getKey());
+            Files.write(configFile, config.getValue());
         }
 
-        // checking if all startup, installed, and boot features have been 
resolved
-        getLog().info("Checking features resolution");
-        List<String> resolvedFeaturesNames = new ArrayList<>();
-        for (Feature feature : features.keySet()) {
-            resolvedFeaturesNames.add(feature.getName());
+        //
+        // Compute startup
+        //
+        Profile startupOverlay = Profiles.getOverlay(startupProfile, 
allProfiles);
+        Profile startupEffective = Profiles.getEffective(startupOverlay, 
false);
+        // Load startup repositories
+        Map<String, Features> startupRepositories = 
loadRepositories(startupEffective.getRepositories());
+        // Compute startup feature dependencies
+        Set<Feature> allStartupFeatures = new HashSet<>();
+        for (Features repo : startupRepositories.values()) {
+            allStartupFeatures.addAll(repo.getFeature());
         }
-        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)");
-                }
+        Set<Feature> startupFeatures = new LinkedHashSet<>();
+        if (startupEffective.getFeatures().isEmpty() && 
installAllFeaturesByDefault) {
+            startupFeatures.addAll(allStartupFeatures);
+        } else {
+            for (String feature : startupEffective.getFeatures()) {
+                addFeatures(startupFeatures, allStartupFeatures, feature);
             }
         }
-        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)");
+        // Compute all bundles
+        Map<String, Integer> allStartupBundles = new LinkedHashMap<>();
+        for (Feature feature : startupFeatures) {
+            for (Bundle bundleInfo : feature.getBundle()) {
+                String bundleLocation = bundleInfo.getLocation();
+                int bundleStartLevel = bundleInfo.getStartLevel() == 0 ? 
defaultStartLevel : bundleInfo.getStartLevel();
+                if (allStartupBundles.containsKey(bundleLocation)) {
+                    bundleStartLevel = Math.min(bundleStartLevel, 
allStartupBundles.get(bundleLocation));
                 }
+                allStartupBundles.put(bundleLocation, bundleStartLevel);
             }
-        }
-        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)");
+            // Install config
+            for (Config config : feature.getConfig()) {
+                installConfig(config);
+            }
+            for (Conditional cond : feature.getConditional()) {
+                for (Config config : cond.getConfig()) {
+                    installConfig(config);
                 }
             }
-        }
-
-        // 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("", "# 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 (useReferenceUrls) {
-                            bundleLocation = "reference:file:" + 
dependencyHelper.pathFromMaven(bundleLocation);
-                        }
-                        if (startupProperties.containsKey(bundleLocation)) {
-                            int oldStartLevel = 
Integer.decode(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;
-                            }
-                        }
+            // Install config files
+            for (ConfigFile configFile : feature.getConfigfile()) {
+                try (InputStream is = new 
URL(configFile.getLocation()).openStream()) {
+                    String path = configFile.getFinalname();
+                    if (path.startsWith("/")) {
+                        path = path.substring(1);
                     }
-                    // add the feature in the system folder
-                    resolveFeature(feature, features, true);
-                } 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(featuresCfgFile);
-                        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();
-                        }
-                    }
-                    // add the feature in the system folder
-                    resolveFeature(feature, features, false);
-                } 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, false);
-                } 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<String> startupBundles = startupProperties.keySet();
-        for (String startupBundle : startupBundles) {
-            if (startupBundle.startsWith("mvn:")) {
-                String bundlePath = 
this.dependencyHelper.pathFromMaven(startupBundle);
-                File bundleFile = new File(system.resolve(bundlePath));
-                if (!bundleFile.exists()) {
-                    File bundleSource = 
this.dependencyHelper.resolveById(startupBundle, getLog());
-                    bundleFile.getParentFile().mkdirs();
-                    copy(bundleSource, bundleFile);
+                    Path output = workDirectory.toPath().resolve(path);
+                    Files.copy(is, output, 
StandardCopyOption.REPLACE_EXISTING);  // TODO: be smarter about overwrites
                 }
-            } else if (startupBundle.startsWith("reference:file:")) {
-                String bundlePath = 
startupBundle.substring("reference:file:".length());
-                File bundleFile = new File(system.resolve(bundlePath));
-                if (!bundleFile.exists()) {
-                    File bundleSource = 
this.dependencyHelper.resolveById(MavenUtil.pathToMvn(bundlePath), getLog());
-                    bundleFile.getParentFile().mkdirs();
-                    copy(bundleSource, bundleFile);
+            }
+            for (Conditional cond : feature.getConditional()) {
+                for (ConfigFile configFile : cond.getConfigfile()) {
+                    try (InputStream is = new 
URL(configFile.getLocation()).openStream()) {
+                        Path output = 
workDirectory.toPath().resolve(configFile.getFinalname());
+                        Files.copy(is, output, 
StandardCopyOption.REPLACE_EXISTING); // TODO: be smarter about overwrites
+                    }
                 }
             }
         }
-
-        // generate the startup.properties file
-        getLog().info("Generating the startup.properties file");
-        try {
-            OutputStream out = new FileOutputStream(startupPropertiesFile);
-            try {
-                startupProperties.save(out);
-            } finally {
-                out.close();
+        for (String bundleLocation : startupEffective.getBundles()) {
+            int bundleStartLevel = defaultStartLevel;
+            if (allStartupBundles.containsKey(bundleLocation)) {
+                bundleStartLevel = Math.min(bundleStartLevel, 
allStartupBundles.get(bundleLocation));
             }
-        } catch (IOException e) {
-            throw new MojoFailureException("Can not write " + 
startupPropertiesFile, e);
+            allStartupBundles.put(bundleLocation, bundleStartLevel);
         }
-    }
-
-    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);
-            }
-        }
-        // resolving repository location
-        File repositoryFile;
-        if (repository.startsWith("mvn")) {
-            repositoryFile = dependencyHelper.resolveById(repository, 
getLog());
-            repository = dependencyHelper.pathFromMaven(repository);
-        } else {
-            repositoryFile = new File(repository);
+        // Load startup.properties
+        startupPropertiesFile.getParentFile().mkdirs();
+        Properties startupProperties = new Properties(startupPropertiesFile);
+        if (!startupPropertiesFile.exists()) {
+            startupProperties.setHeader(Collections.singletonList("# Bundles 
to be started on startup, with startlevel"));
         }
-        // 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(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");
-                    }
+        // Install bundles and update startup.properties
+        Map<Integer, Set<String>> invertedStartupBundles = 
MapUtils.invert(allStartupBundles);
+        for (Map.Entry<Integer, Set<String>> entry : 
invertedStartupBundles.entrySet()) {
+            String startLevel = Integer.toString(entry.getKey());
+            for (String location : new TreeSet<>(entry.getValue())) {
+                location = installStartupArtifact(location, useReferenceUrls);
+                if (location.startsWith("file:") && useReferenceUrls) {
+                    location = "reference:" + location;
                 }
+                startupProperties.put(location, startLevel);
             }
         }
-        // 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);
+        // generate the startup.properties file
+        startupProperties.save();
+
+
+        //
+        // Handle boot profiles
+        //
+        Profile bootOverlay = Profiles.getOverlay(bootProfile, allProfiles);
+        Profile bootEffective = Profiles.getEffective(bootOverlay, false);
+        // Load startup repositories
+        Map<String, Features> bootRepositories = 
loadRepositories(bootEffective.getRepositories());
+        // Compute startup feature dependencies
+        Set<Feature> allBootFeatures = new HashSet<>();
+        for (Features repo : bootRepositories.values()) {
+            allBootFeatures.addAll(repo.getFeature());
         }
-        // update features
-        for (Feature feature : featuresModel.getFeature()) {
-            features.put(feature, updateStartupProperties);
+        // Install all repositories
+        for (String repository : bootRepositories.keySet()) {
+            installArtifact(repository);
         }
-    }
-
-    private void resolveFeature(Feature feature, Map<Feature, Boolean> 
features, boolean installConfig) throws Exception {
-        for (Dependency dependency : feature.getFeature()) {
-            for (Feature f : features.keySet()) {
-                if (f.getName().equals(dependency.getName())) {
-                    resolveFeature(f, features, installConfig);
+        // Generate a global feature
+        Map<String, Dependency> generatedDep = new HashMap<>();
+        Feature generated = new Feature();
+        generated.setName(UUID.randomUUID().toString());
+        // Add feature dependencies
+        if (bootEffective.getFeatures().isEmpty()) {
+            if (installAllFeaturesByDefault) {
+                for (Features repo : bootRepositories.values()) {
+                    for (Feature feature : repo.getFeature()) {
+                        Dependency dep = generatedDep.get(feature.getName());
+                        if (dep == null) {
+                            dep = new Dependency();
+                            dep.setName(feature.getName());
+                            generated.getFeature().add(dep);
+                            generatedDep.put(dep.getName(), dep);
+                        }
+                        dep.setDependency(false);
+                    }
+                }
+            }
+        } else {
+            for (String dependency : bootEffective.getFeatures()) {
+                Dependency dep = generatedDep.get(dependency);
+                if (dep == null) {
+                    dep = new Dependency();
+                    dep.setName(dependency);
+                    generated.getFeature().add(dep);
+                    generatedDep.put(dep.getName(), dep);
                 }
+                dep.setDependency(false);
             }
         }
-
-        getLog().info("Resolving feature " + feature.getName());
-
-        // installing feature bundles
-        getLog().info("= Installing bundles from " + feature.getName() + " 
feature");
-        for (Bundle bundle : feature.getBundle()) {
-            installBundle(bundle);
+        // Add bundles
+        for (String location : bootEffective.getBundles()) {
+            location = location.replace("profile:", "file:etc/");
+            Bundle bun = new Bundle();
+            bun.setLocation(location);
+            generated.getBundle().add(bun);
         }
-
-        // installing feature config files
-        getLog().info("= Installing configuration files from " + 
feature.getName() + " feature");
-        if (installConfig) {
-            for (Config config : feature.getConfig()) {
-                installConfig(config);
+        Features rep = new Features();
+        rep.setName(UUID.randomUUID().toString());
+        rep.getRepository().addAll(bootEffective.getRepositories());
+        rep.getFeature().add(generated);
+        allBootFeatures.add(generated);
+
+        // Compute startup feature dependencies
+        Set<Feature> bootFeatures = new HashSet<>();
+        addFeatures(bootFeatures, allBootFeatures, generated.getName());
+        for (Feature feature : bootFeatures) {
+            // the feature is a startup feature, updating startup.properties 
file
+            getLog().info("Feature " + feature.getName() + " is defined as a 
boot feature");
+            // add the feature in the system folder
+            Set<String> locations = new HashSet<>();
+            for (Bundle bundle : feature.getBundle()) {
+                if (!ignoreDependencyFlag || !bundle.isDependency()) {
+                    locations.add(bundle.getLocation());
+                }
             }
-        }
-        for (ConfigFile configFile : feature.getConfigfile()) {
-            installConfigFile(configFile, installConfig);
-        }
-
-        // installing condition features
-        for (Conditional conditional : feature.getConditional()) {
-//            boolean found = true;
-//            for (String condition : conditional.getCondition()) {
-//                if (!condition.startsWith("req:")) {
-//                    if ((installedFeatures != null && 
!installedFeatures.contains(condition)) && (bootFeatures != null && 
!bootFeatures.contains(condition))) {
-//                        found = false;
-//                        break;
-//                    }
-//                }
-//            }
-//            if (found) {
-                getLog().info("= Installing conditional " + 
conditional.getCondition().toString());
-                getLog().debug("== Conditional features ...");
-                for (Dependency dependency : conditional.getFeature()) {
-                    for (Feature f : features.keySet()) {
-                        if (f.getName().equals(dependency.getName())) {
-                            resolveFeature(f, features, installConfig);
-                        }
+            for (Conditional cond : feature.getConditional()) {
+                for (Bundle bundle : cond.getBundle()) {
+                    if (!ignoreDependencyFlag || !bundle.isDependency()) {
+                        locations.add(bundle.getLocation());
                     }
                 }
-                getLog().debug("== Conditional bundles");
-                for (Bundle bundle : conditional.getBundle()) {
-                    installBundle(bundle);
-                }
-                getLog().debug("== Conditional configuration files");
-                if (installConfig) {
-                    for (Config config : conditional.getConfig()) {
-                        installConfig(config);
+            }
+            for (String location : locations) {
+                installArtifact(location);
+                for (Map.Entry<String, List<String>> entry : 
prereqs.entrySet()) {
+                    if (location.startsWith(entry.getKey())) {
+                        for (String prereq : entry.getValue()) {
+                            Dependency dep = generatedDep.get(prereq);
+                            if (dep == null) {
+                                dep = new Dependency();
+                                dep.setName(prereq);
+                                generated.getFeature().add(dep);
+                                generatedDep.put(dep.getName(), dep);
+                            }
+                            dep.setPrerequisite(true);
+                        }
                     }
                 }
-                for (ConfigFile configFile : conditional.getConfigfile()) {
-                    installConfigFile(configFile, installConfig);
+            }
+            // Install config files
+            for (ConfigFile configFile : feature.getConfigfile()) {
+                installArtifact(configFile.getLocation());
+            }
+            for (Conditional cond : feature.getConditional()) {
+                for (ConfigFile configFile : cond.getConfigfile()) {
+                    installArtifact(configFile.getLocation());
                 }
-//            }
+            }
         }
-    }
 
-    private void installBundle(Bundle bundle) throws Exception {
-        if (!ignoreDependencyFlag && bundle.isDependency()) {
-            getLog().warn("== Bundle " + bundle.getLocation() + " is defined 
as dependency, so it's not installed");
-        } else {
-            getLog().info("== Installing bundle " + bundle.getLocation());
-            String bundleLocation = bundle.getLocation();
-            // cleanup prefixes
-            if (bundleLocation.startsWith("wrap:")) {
-                bundleLocation = bundleLocation.substring("wrap:".length());
-                int index = bundleLocation.indexOf("$");
-                if (index != -1) {
-                    bundleLocation = bundleLocation.substring(0, index);
-                }
+        // If there are bundles to install, we can't use the boot features only
+        // so keep the generated feature
+        if (!generated.getBundle().isEmpty()) {
+            File output = new File(workDirectory, "etc/" + rep.getName() + 
".xml");
+            try (FileOutputStream os = new FileOutputStream(output)) {
+                JaxbUtil.marshal(rep, os);
             }
-            if (bundleLocation.startsWith("blueprint:")) {
-                bundleLocation = 
bundleLocation.substring("blueprint:".length());
+            Properties featuresProperties = new Properties(featuresCfgFile);
+            featuresProperties.put(FEATURES_REPOSITORIES, 
"file:${karaf.home}/etc/" + output.getName());
+            featuresProperties.put(FEATURES_BOOT, generated.getName());
+            featuresProperties.save();
+        }
+        else {
+            String boot = "";
+            for (Dependency dep : generatedDep.values()) {
+                if (dep.isPrerequisite()) {
+                    if (boot.isEmpty()) {
+                        boot = "(";
+                    } else {
+                        boot = boot + ",";
+                    }
+                    boot = boot + dep.getName();
+                }
             }
-            if (bundleLocation.startsWith("webbundle:")) {
-                bundleLocation = 
bundleLocation.substring("webbundle:".length());
+            if (!boot.isEmpty()) {
+                boot = boot + ")";
             }
-            if (bundleLocation.startsWith("war:")) {
-                bundleLocation = bundleLocation.substring("war:".length());
+            // TODO: for dependencies, we'd need to resolve the features 
completely
+            for (Dependency dep : generatedDep.values()) {
+                if (!dep.isPrerequisite() && !dep.isDependency()) {
+                    if (!boot.isEmpty()) {
+                        boot = boot + ",";
+                    }
+                    boot = boot + dep.getName();
+                }
             }
-            File bundleFile;
-            if (bundleLocation.startsWith("mvn:")) {
-                if (bundleLocation.endsWith("/")) {
-                    // for bad formed URL (like in Camel for 
mustache-compiler), we remove the trailing /
-                    bundleLocation = bundleLocation.substring(0, 
bundleLocation.length() - 1);
+            String repos = "";
+            for (String repo : new HashSet<>(rep.getRepository())) {
+                if (!repos.isEmpty()) {
+                    repos = repos + ",";
                 }
-                if (bundleLocation.startsWith("mvn:http")) {
-                    // cleanup the URL containing the repository location 
directly in the URL
-                    int index = bundleLocation.indexOf("!");
-                    if (index != -1) {
-                        bundleLocation = bundleLocation.substring(index + 1);
-                        bundleLocation = "mvn:" + bundleLocation;
-                    }
+                repos = repos + repo;
+            }
+
+            Properties featuresProperties = new Properties(featuresCfgFile);
+            featuresProperties.put(FEATURES_REPOSITORIES, repos);
+            featuresProperties.put(FEATURES_BOOT, boot);
+            featuresProperties.save();
+        }
+
+
+        //
+        // Handle installed profiles
+        //
+        Profile installedOverlay = Profiles.getOverlay(installedProfile, 
allProfiles);
+        Profile installedEffective = Profiles.getEffective(installedOverlay, 
false);
+
+        // Load startup repositories
+        Map<String, Features> installedRepositories = 
loadRepositories(installedEffective.getRepositories());
+        // Install all repositories
+        for (String repository : installedRepositories.keySet()) {
+            installArtifact(repository);
+        }
+        // Compute startup feature dependencies
+        Set<Feature> allInstalledFeatures = new HashSet<>();
+        for (Features repo : installedRepositories.values()) {
+            allInstalledFeatures.addAll(repo.getFeature());
+        }
+        Set<Feature> installedFeatures = new LinkedHashSet<>();
+        if (installedEffective.getFeatures().isEmpty() && 
installAllFeaturesByDefault) {
+            installedFeatures.addAll(allInstalledFeatures);
+        } else {
+            // Add boot features for search
+            allInstalledFeatures.addAll(allBootFeatures);
+            for (String feature : installedEffective.getFeatures()) {
+                addFeatures(installedFeatures, allInstalledFeatures, feature);
+            }
+        }
+        for (Feature feature : installedFeatures) {
+            for (Bundle bundle : feature.getBundle()) {
+                if (!ignoreDependencyFlag || !bundle.isDependency()) {
+                    installArtifact(bundle.getLocation());
                 }
-                bundleFile = dependencyHelper.resolveById(bundleLocation, 
getLog());
-                bundleLocation = 
dependencyHelper.pathFromMaven(bundleLocation);
-            } else {
-                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");
+            for (Conditional cond : feature.getConditional()) {
+                for (Bundle bundle : cond.getBundle()) {
+                    if (!ignoreDependencyFlag || !bundle.isDependency()) {
+                        installArtifact(bundle.getLocation());
                     }
                 }
             }
         }
+        for (String location : installedEffective.getBundles()) {
+            installArtifact(location);
+        }
+        // TODO: install config files
     }
 
-    private void installConfig(Config config) throws Exception {
-        getLog().info("== Installing configuration " + config.getName());
+    private Map<String, Features> loadRepositories(List<String> repositories) 
throws Exception {
+        Map<String, Features> loaded = new HashMap<>();
+        for (String repository : repositories) {
+            doLoadRepository(loaded, repository);
+        }
+        return loaded;
+    }
 
-        Path configFile = Paths.get(workDirectory, "etc", config.getName());
-        Files.write(configFile, config.getValue().getBytes());
+    private void doLoadRepository(Map<String, Features> loaded, String 
repository) throws Exception {
+        if (!loaded.containsKey(repository)) {
+            Features featuresModel = JaxbUtil.unmarshal(repository, false);
+            loaded.put(repository, featuresModel);
+            // recursively process the inner repositories
+            for (String innerRepository : featuresModel.getRepository()) {
+                doLoadRepository(loaded, innerRepository);
+            }
+        }
     }
 
-    private void installConfigFile(ConfigFile configFile, boolean 
installConfig) throws Exception {
-        getLog().info("== 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));
+    private Profile generateProfile(Map<String, Profile> allProfiles, 
List<String> profiles, List<String> repositories, List<String> features, 
List<String> bundles) {
+        Profile profile = 
ProfileBuilder.Factory.create(UUID.randomUUID().toString())
+                .setParents(profiles)
+                .setRepositories(repositories)
+                .setFeatures(features)
+                .setBundles(bundles)
+                .getProfile();
+        allProfiles.put(profile.getId(), profile);
+        return profile;
+    }
+
+    private List<String> nonNullList(List<String> list) {
+        return list == null ? new ArrayList<String>() : list;
+    }
+
+    private void addFeatures(Set<Feature> startupFeatures, Set<Feature> 
features, String feature) {
+        int nbFound = 0;
+        for (Feature f : features) {
+            if (feature.equals(f.getName())) {
+                for (Dependency dep : f.getFeature()) {
+                    addFeatures(startupFeatures, features, dep.getName());
+                }
+                startupFeatures.add(f);
+                nbFound++;
+            }
+        }
+        if (nbFound == 0) {
+            throw new IllegalStateException("Could not find matching feature 
for " + feature);
         }
-        if (installConfig) {
-            copy(configFileFile, new File(workDirectory + "/" + 
configFile.getFinalname()));
+    }
+
+    private String installStartupArtifact(String location, boolean asFile) 
throws Exception {
+        getLog().info("== Installing artifact " + location);
+        String url;
+        String path;
+        if (location.startsWith("mvn:")) {
+            url = location;
+            path = dependencyHelper.pathFromMaven(location);
+            if (asFile) {
+                location = "file:" + path ;
+            }
         } else {
-            File configFileSystemFile = new 
File(system.resolve(configFileLocation));
-            copy(configFileFile, configFileSystemFile);
+            url = location.replace("profile:", "file:" + 
workDirectory.getAbsolutePath() + "/etc/");
+            path = "generated/" + location.replaceAll("[^0-9a-zA-Z.\\-_]+", 
"_");
+            location = "file:" + path;
+        }
+        File bundleSystemFile = new File(systemDirectory, path);
+        if (!bundleSystemFile.exists()) {
+            bundleSystemFile.getParentFile().mkdirs();
+            try (InputStream is = new URL(url).openStream()) {
+                Files.copy(is, bundleSystemFile.toPath());
+            }
+        }
+        return location;
+    }
+
+    private void installArtifact(String location) throws Exception {
+        getLog().info("== Installing artifact " + location);
+        location = DownloadManagerHelper.stripUrl(location);
+        location = 
DownloadManagerHelper.removeInlinedMavenRepositoryUrl(location);
+        if (location.startsWith("mvn:")) {
+            if (location.endsWith("/")) {
+                // for bad formed URL (like in Camel for mustache-compiler), 
we remove the trailing /
+                location = location.substring(0, location.length() - 1);
+            }
+            File inputFile = dependencyHelper.resolveById(location, getLog());
+            File targetFile = new File(systemDirectory, 
dependencyHelper.pathFromMaven(location));
+            copy(inputFile, targetFile);
             // 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");
-                    }
+            Artifact artifact = dependencyHelper.mvnToArtifact(location);
+            if (artifact.isSnapshot()) {
+                File metadataTarget = new File(targetFile.getParentFile(), 
"maven-metadata-local.xml");
+                try {
+                    MavenUtil.generateMavenMetadata(artifact, 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");
                 }
             }
+        } else {
+            getLog().warn("Ignoring artifact " + location);
+        }
+    }
+
+    private void installConfig(Config config) throws Exception {
+        getLog().info("== Installing configuration " + config.getName());
+        Path configFile = workDirectory.toPath().resolve("etc/" + 
config.getName());
+        if (!Files.exists(configFile)) {
+            Files.write(configFile, config.getValue().getBytes());
+        } else if (config.isAppend()) {
+            // TODO
         }
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
----------------------------------------------------------------------
diff --git 
a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
 
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
index f03d923..0692b53 100644
--- 
a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
+++ 
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
@@ -36,6 +36,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Dictionary;
 import java.util.EnumSet;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -48,6 +49,8 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.jar.Attributes;
 import java.util.jar.Manifest;
@@ -66,7 +69,7 @@ import org.apache.karaf.features.FeatureEvent;
 import org.apache.karaf.features.FeaturesService;
 import org.apache.karaf.features.Repository;
 import org.apache.karaf.features.internal.download.DownloadManager;
-import org.apache.karaf.features.internal.download.simple.SimpleDownloader;
+import org.apache.karaf.features.internal.download.DownloadManagers;
 import org.apache.karaf.features.internal.resolver.ResourceBuilder;
 import org.apache.karaf.features.internal.resolver.ResourceImpl;
 import org.apache.karaf.features.internal.resolver.ResourceUtils;
@@ -75,6 +78,9 @@ import 
org.apache.karaf.features.internal.service.RepositoryImpl;
 import org.apache.karaf.features.internal.service.State;
 import org.apache.karaf.features.internal.util.MapUtils;
 import org.apache.karaf.features.internal.util.MultiException;
+import org.apache.karaf.tooling.url.CustomBundleURLStreamHandlerFactory;
+import org.apache.karaf.tooling.utils.InternalMavenResolver;
+import org.apache.karaf.tooling.utils.MojoSupport;
 import org.apache.karaf.tooling.utils.PropertiesLoader;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.AbstractMojo;
@@ -84,7 +90,10 @@ import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
 import org.apache.maven.project.MavenProject;
+import org.ops4j.pax.url.mvn.MavenResolver;
+import org.ops4j.pax.url.mvn.MavenResolvers;
 import org.ops4j.pax.url.mvn.ServiceConstants;
+import org.ops4j.pax.url.mvn.internal.AetherBasedResolver;
 import org.ops4j.pax.url.mvn.internal.Connection;
 import org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl;
 import org.osgi.framework.Bundle;
@@ -105,7 +114,7 @@ import 
shaded.org.ops4j.util.property.PropertiesPropertyResolver;
 import static java.util.jar.JarFile.MANIFEST_NAME;
 
 @Mojo(name = "verify-features", requiresDependencyResolution = 
ResolutionScope.COMPILE_PLUS_RUNTIME)
-public class VerifyFeatureResolutionMojo extends AbstractMojo {
+public class VerifyFeatureResolutionMojo extends MojoSupport {
 
     @Parameter(property = "descriptors")
     protected Set<String> descriptors;
@@ -143,21 +152,24 @@ public class VerifyFeatureResolutionMojo extends 
AbstractMojo {
     @Parameter(defaultValue = "${project}", readonly = true)
     protected MavenProject project;
 
+    protected MavenResolver resolver;
+
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
+        DependencyHelper helper = 
DependencyHelperFactory.createDependencyHelper(this.container, this.project, 
this.mavenSession, getLog());
+        resolver = new InternalMavenResolver(helper, getLog());
+        CustomBundleURLStreamHandlerFactory.install(resolver);
         try {
-            Field field = URL.class.getDeclaredField("factory");
-            field.setAccessible(true);
-            field.set(null, null);
-        } catch (Exception e) {
-            e.printStackTrace();
+            doExecute();
+        } finally {
+            CustomBundleURLStreamHandlerFactory.uninstall();
         }
-        URL.setURLStreamHandlerFactory(new 
CustomBundleURLStreamHandlerFactory());
+    }
 
+    protected void doExecute() throws MojoExecutionException, 
MojoFailureException {
         System.setProperty("karaf.home", "target/karaf");
         System.setProperty("karaf.data", "target/karaf/data");
 
-
         Hashtable<String, String> properties = new Hashtable<>();
 
         if (additionalMetadata != null) {
@@ -174,7 +186,9 @@ public class VerifyFeatureResolutionMojo extends 
AbstractMojo {
             }
         }
 
-        DownloadManager manager = new SimpleDownloader();
+        // TODO: allow using external configuration ?
+        ScheduledExecutorService executor = 
Executors.newScheduledThreadPool(8);
+        DownloadManager manager = 
DownloadManagers.createDownloadManager(resolver, executor);
         final Map<String, Repository> repositories;
         Map<String, Feature[]> allFeatures = new HashMap<>();
         try {
@@ -489,32 +503,6 @@ public class VerifyFeatureResolutionMojo extends 
AbstractMojo {
         return result;
     }
 
-    public static class CustomBundleURLStreamHandlerFactory implements 
URLStreamHandlerFactory {
-
-        public URLStreamHandler createURLStreamHandler(String protocol) {
-            switch (protocol) {
-            case "mvn":
-                return new URLStreamHandler() {
-                    @Override
-                    protected URLConnection openConnection(URL url) throws 
IOException {
-                        PropertiesPropertyResolver propertyResolver = new 
PropertiesPropertyResolver(System.getProperties());
-                        final MavenConfigurationImpl config = new 
MavenConfigurationImpl(propertyResolver, ServiceConstants.PID);
-                        return new Connection(url, config);
-                    }
-                };
-            case "wrap":
-                return new org.ops4j.pax.url.wrap.Handler();
-            case "blueprint":
-                return new 
org.apache.karaf.deployer.blueprint.BlueprintURLHandler();
-            case "war":
-                return new org.ops4j.pax.url.war.Handler();
-            default:
-                return null;
-            }
-        }
-
-    }
-
     public static Map<String, Map<VersionRange, Map<String, String>>> 
getMetadata(Map<String, String> properties, String prefix) {
         Map<String, Map<VersionRange, Map<String, String>>> result = new 
HashMap<>();
         for (String key : properties.keySet()) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java
----------------------------------------------------------------------
diff --git 
a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java
 
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java
index 422d680..d6fc156 100644
--- 
a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java
+++ 
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java
@@ -17,8 +17,21 @@
  */
 package org.apache.karaf.tooling.url;
 
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.net.URLConnection;
 import java.net.URLStreamHandler;
 import java.net.URLStreamHandlerFactory;
+import java.util.Hashtable;
+
+import org.ops4j.pax.url.mvn.MavenResolver;
+import org.ops4j.pax.url.mvn.MavenResolvers;
+import org.ops4j.pax.url.mvn.ServiceConstants;
+import org.ops4j.pax.url.mvn.internal.AetherBasedResolver;
+import org.ops4j.pax.url.mvn.internal.Connection;
+import org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl;
+import shaded.org.ops4j.util.property.PropertiesPropertyResolver;
 
 public class CustomBundleURLStreamHandlerFactory implements 
URLStreamHandlerFactory {
 
@@ -29,9 +42,30 @@ public class CustomBundleURLStreamHandlerFactory implements 
URLStreamHandlerFact
     private static final String BLUEPRINT_URI_PREFIX = "blueprint";
     private static final String WAR_URI_PREFIX = "war";
 
-    public URLStreamHandler createURLStreamHandler(String protocol) {
+       private final MavenResolver mavenResolver;
+
+       public CustomBundleURLStreamHandlerFactory() {
+               this(null);
+       }
+
+       public CustomBundleURLStreamHandlerFactory(MavenResolver mavenResolver) 
{
+               this.mavenResolver = mavenResolver;
+       }
+
+       public URLStreamHandler createURLStreamHandler(String protocol) {
                if (protocol.equals(MVN_URI_PREFIX)) {
-                       return new org.ops4j.pax.url.mvn.Handler();
+                       return new URLStreamHandler() {
+                               @Override
+                               protected URLConnection openConnection(URL u) 
throws IOException {
+                                       MavenResolver resolver = mavenResolver;
+                                       if (resolver == null) {
+                                               PropertiesPropertyResolver 
propertyResolver = new PropertiesPropertyResolver(System.getProperties());
+                                               final MavenConfigurationImpl 
config = new MavenConfigurationImpl(propertyResolver, ServiceConstants.PID);
+                                               resolver = new 
AetherBasedResolver(config);
+                                       }
+                                       return new Connection(u, resolver);
+                               }
+                       };
                } else if (protocol.equals(WRAP_URI_PREFIX)){
                        return new org.ops4j.pax.url.wrap.Handler();
                } else if (protocol.equals(FEATURE_URI_PREFIX)){
@@ -47,4 +81,26 @@ public class CustomBundleURLStreamHandlerFactory implements 
URLStreamHandlerFact
                }
        }
 
+       public static void install() {
+               install(null);
+       }
+
+       public static void install(MavenResolver mavenResolver) {
+               uninstall();
+               URL.setURLStreamHandlerFactory(new 
CustomBundleURLStreamHandlerFactory(mavenResolver));
+       }
+
+       public static void uninstall() {
+               try {
+                       Field handlersField = 
URL.class.getDeclaredField("handlers");
+                       Field factoryField = 
URL.class.getDeclaredField("factory");
+                       factoryField.setAccessible(true);
+                       factoryField.set(null, null);
+                       handlersField.setAccessible(true);
+                       handlersField.set(null, new Hashtable());
+               } catch (Throwable t) {
+                       t.printStackTrace();
+               }
+       }
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/InternalMavenResolver.java
----------------------------------------------------------------------
diff --git 
a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/InternalMavenResolver.java
 
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/InternalMavenResolver.java
new file mode 100644
index 0000000..8d4b3f4
--- /dev/null
+++ 
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/InternalMavenResolver.java
@@ -0,0 +1,70 @@
+/**
+ *
+ * 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.
+ */
+package org.apache.karaf.tooling.utils;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.karaf.tooling.features.DependencyHelper;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.ops4j.pax.url.mvn.MavenResolver;
+
+public class InternalMavenResolver implements MavenResolver {
+
+    private final DependencyHelper dependencyHelper;
+    private final Log log;
+
+    public InternalMavenResolver(DependencyHelper dependencyHelper, Log log) {
+        this.dependencyHelper = dependencyHelper;
+        this.log = log;
+    }
+
+    @Override
+    public File resolve(String url) throws IOException {
+        try {
+            return dependencyHelper.resolveById(url, log);
+        } catch (MojoFailureException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public File resolve(String groupId, String artifactId, String classifier, 
String extension, String version) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File resolveMetadata(String groupId, String artifactId, String 
type, String version) throws IOException {
+        return null;
+    }
+
+    @Override
+    public void upload(String groupId, String artifactId, String classifier, 
String extension, String version, File artifact) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void uploadMetadata(String groupId, String artifactId, String type, 
String version, File artifact) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void close() throws IOException {
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/IoUtils.java
----------------------------------------------------------------------
diff --git 
a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/IoUtils.java
 
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/IoUtils.java
new file mode 100644
index 0000000..3069608
--- /dev/null
+++ 
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/IoUtils.java
@@ -0,0 +1,38 @@
+/**
+ *
+ * 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.
+ */
+package org.apache.karaf.tooling.utils;
+
+import java.io.File;
+
+public class IoUtils {
+
+    public static void deleteRecursive(File file) {
+        if (file != null) {
+            if (file.isDirectory()) {
+                File[] children = file.listFiles();
+                if (children != null) {
+                    for (File child : children) {
+                        deleteRecursive(child);
+                    }
+                }
+            }
+            file.delete();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java
----------------------------------------------------------------------
diff --git 
a/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java
 
b/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java
index 46d7252..eea50c0 100644
--- 
a/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java
+++ 
b/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java
@@ -17,7 +17,6 @@
 package org.apache.karaf.tooling.tracker;
 
 import java.io.File;
-import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
@@ -27,7 +26,6 @@ import org.apache.karaf.util.tracker.ProvideService;
 import org.apache.karaf.util.tracker.RequireService;
 import org.apache.karaf.util.tracker.Services;
 import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.DependencyResolutionRequiredException;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;

http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java
----------------------------------------------------------------------
diff --git 
a/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java 
b/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java
index d55a7de..149947c 100644
--- a/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java
+++ b/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java
@@ -136,6 +136,9 @@ public class BaseActivator implements BundleActivator, 
SingleServiceTracker.Sing
         reconfigure();
     }
 
+    protected Dictionary<String, ?> getConfiguration() {
+        return configuration;
+    }
     /**
      * Called in {@link #doStart()}
      */

Reply via email to