You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2015/04/17 11:34:56 UTC

[4/5] karaf git commit: [KARAF-3671] Clean up karaf-maven-plugin goals

http://git-wip-us.apache.org/repos/asf/karaf/blob/056239dc/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/VerifyMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/VerifyMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/VerifyMojo.java
new file mode 100644
index 0000000..db8a9c5
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/VerifyMojo.java
@@ -0,0 +1,805 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+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;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import aQute.bnd.osgi.Macro;
+import aQute.bnd.osgi.Processor;
+import org.apache.felix.resolver.Logger;
+import org.apache.felix.resolver.ResolverImpl;
+import org.apache.felix.utils.version.VersionRange;
+import org.apache.felix.utils.version.VersionTable;
+import org.apache.karaf.features.FeatureEvent;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.internal.download.DownloadCallback;
+import org.apache.karaf.features.internal.download.DownloadManager;
+import org.apache.karaf.features.internal.download.Downloader;
+import org.apache.karaf.features.internal.download.StreamProvider;
+import org.apache.karaf.features.internal.model.Conditional;
+import org.apache.karaf.features.internal.model.ConfigFile;
+import org.apache.karaf.features.internal.model.Feature;
+import org.apache.karaf.features.internal.model.Features;
+import org.apache.karaf.features.internal.model.JaxbUtil;
+import org.apache.karaf.features.internal.resolver.ResourceBuilder;
+import org.apache.karaf.features.internal.resolver.ResourceImpl;
+import org.apache.karaf.features.internal.resolver.ResourceUtils;
+import org.apache.karaf.features.internal.service.Deployer;
+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.profile.assembly.CustomDownloadManager;
+import org.apache.karaf.tooling.utils.MojoSupport;
+import org.apache.karaf.util.config.PropertiesLoader;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+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.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.startlevel.BundleStartLevel;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
+import org.osgi.service.resolver.ResolutionException;
+
+import static java.util.jar.JarFile.MANIFEST_NAME;
+
+@Mojo(name = "verify", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
+public class VerifyMojo extends MojoSupport {
+
+    @Parameter(property = "descriptors")
+    protected Set<String> descriptors;
+
+    @Parameter(property = "features")
+    protected Set<String> features;
+
+    @Parameter(property = "framework")
+    protected Set<String> framework;
+
+    @Parameter(property = "configuration")
+    protected String configuration;
+
+    @Parameter(property = "distribution", defaultValue = "org.apache.karaf:apache-karaf")
+    protected String distribution;
+
+    @Parameter(property = "javase")
+    protected String javase;
+
+    @Parameter(property = "dist-dir")
+    protected String distDir;
+
+    @Parameter(property = "additional-metadata")
+    protected File additionalMetadata;
+
+    @Parameter(property = "ignore-missing-conditions")
+    protected boolean ignoreMissingConditions;
+
+    @Parameter(property = "fail")
+    protected String fail = "end";
+
+    @Parameter(property = "verify-transitive")
+    protected boolean verifyTransitive = false;
+
+    @Parameter(defaultValue = "${project}", readonly = true)
+    protected MavenProject project;
+
+    protected MavenResolver resolver;
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        Hashtable<String, String> config = new Hashtable<>();
+        StringBuilder remote = new StringBuilder();
+        for (Object obj : project.getRemoteProjectRepositories()) {
+            if (remote.length() > 0) {
+                remote.append(",");
+            }
+            remote.append(invoke(obj, "getUrl"));
+            remote.append("@id=").append(invoke(obj, "getId"));
+            if (!((Boolean) invoke(getPolicy(obj, false), "isEnabled"))) {
+                remote.append("@noreleases");
+            }
+            if ((Boolean) invoke(getPolicy(obj, true), "isEnabled")) {
+                remote.append("@snapshots");
+            }
+        }
+        getLog().info("Using repositories: " + remote.toString());
+        config.put("maven.repositories", remote.toString());
+        // TODO: add more configuration bits ?
+        resolver = MavenResolvers.createMavenResolver(config, "maven");
+        doExecute();
+    }
+
+    private Object invoke(Object object, String getter) throws MojoExecutionException {
+        try {
+            return object.getClass().getMethod(getter).invoke(object);
+        } catch (Exception e) {
+            throw new MojoExecutionException("Unable to build remote repository from " + object.toString(), e);
+        }
+    }
+
+    private Object getPolicy(Object object, boolean snapshots) throws MojoExecutionException {
+        return invoke(object, "getPolicy", new Class[] { Boolean.TYPE }, new Object[] { snapshots });
+    }
+
+    private Object invoke(Object object, String getter, Class[] types, Object[] params) throws MojoExecutionException {
+        try {
+            return object.getClass().getMethod(getter, types).invoke(object, params);
+        } catch (Exception e) {
+            throw new MojoExecutionException("Unable to build remote repository from " + object.toString(), e);
+        }
+    }
+
+    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) {
+            try (Reader reader = new FileReader(additionalMetadata)) {
+                Properties metadata = new Properties();
+                metadata.load(reader);
+                for (Enumeration<?> e = metadata.propertyNames(); e.hasMoreElements(); ) {
+                    Object key = e.nextElement();
+                    Object val = metadata.get(key);
+                    properties.put(key.toString(), val.toString());
+                }
+            } catch (IOException e) {
+                throw new MojoExecutionException("Unable to load additional metadata from " + additionalMetadata, e);
+            }
+        }
+
+        // TODO: allow using external configuration ?
+        ScheduledExecutorService executor = Executors.newScheduledThreadPool(8);
+        DownloadManager manager = new CustomDownloadManager(resolver, executor);
+        final Map<String, Features> repositories;
+        Map<String, List<Feature>> allFeatures = new HashMap<>();
+        try {
+            repositories = loadRepositories(manager, descriptors);
+            for (String repoUri : repositories.keySet()) {
+                List<Feature> features = repositories.get(repoUri).getFeature();
+                // Ack features to inline configuration files urls
+                for (Feature feature : features) {
+                    for (org.apache.karaf.features.internal.model.Bundle bi : feature.getBundle()) {
+                        String loc = bi.getLocation();
+                        String nloc = null;
+                        if (loc.contains("file:")) {
+                            for (ConfigFile cfi : feature.getConfigfile()) {
+                                if (cfi.getFinalname().substring(1)
+                                        .equals(loc.substring(loc.indexOf("file:") + "file:".length()))) {
+                                    nloc = cfi.getLocation();
+                                }
+                            }
+                        }
+                        if (nloc != null) {
+                            Field field = bi.getClass().getDeclaredField("location");
+                            field.setAccessible(true);
+                            field.set(bi, loc.substring(0, loc.indexOf("file:")) + nloc);
+                        }
+                    }
+                }
+                allFeatures.put(repoUri, features);
+            }
+        } catch (Exception e) {
+            throw new MojoExecutionException("Unable to load features descriptors", e);
+        }
+
+        List<Feature> featuresToTest = new ArrayList<>();
+        if (verifyTransitive) {
+            for (List<Feature> features : allFeatures.values()) {
+                featuresToTest.addAll(features);
+            }
+        } else {
+            for (String uri : descriptors) {
+                featuresToTest.addAll(allFeatures.get(uri));
+            }
+        }
+        if (features != null && !features.isEmpty()) {
+            StringBuilder sb = new StringBuilder();
+            for (String feature : features) {
+                if (sb.length() > 0) {
+                    sb.append("|");
+                }
+                String p = feature.replaceAll("\\.", "\\\\.").replaceAll("\\*", ".*");
+                sb.append(p);
+                if (!feature.contains("/")) {
+                    sb.append("/.*");
+                }
+            }
+            Pattern pattern = Pattern.compile(sb.toString());
+            for (Iterator<Feature> iterator = featuresToTest.iterator(); iterator.hasNext();) {
+                Feature feature = iterator.next();
+                String id = feature.getName() + "/" + feature.getVersion();
+                if (!pattern.matcher(id).matches()) {
+                    iterator.remove();
+                }
+            }
+        }
+
+        for (String fmk : framework) {
+            properties.put("feature.framework." + fmk, fmk);
+        }
+        List<Exception> failures = new ArrayList<>();
+        for (Feature feature : featuresToTest) {
+            try {
+                String id = feature.getName() + "/" + feature.getVersion();
+                verifyResolution(manager, repositories, Collections.singleton(id), properties);
+                getLog().info("Verification of feature " + id + " succeeded");
+            } catch (Exception e) {
+                if (e.getCause() instanceof ResolutionException) {
+                    getLog().warn(e.getMessage());
+                } else {
+                    getLog().warn(e);
+                }
+                failures.add(e);
+                if ("first".equals(fail)) {
+                    throw e;
+                }
+            }
+            for (Conditional cond : feature.getConditional()) {
+                Set<String> ids = new LinkedHashSet<>();
+                ids.add(feature.getId());
+                ids.addAll(cond.getCondition());
+                try {
+                    verifyResolution(manager, repositories, ids, properties);
+                    getLog().info("Verification of feature " + ids + " succeeded");
+                } catch (Exception e) {
+                    if (ignoreMissingConditions && e.getCause() instanceof ResolutionException) {
+                        boolean ignore = true;
+                        Collection<Requirement> requirements = ((ResolutionException) e.getCause()).getUnresolvedRequirements();
+                        for (Requirement req : requirements) {
+                            ignore &= (IdentityNamespace.IDENTITY_NAMESPACE.equals(req.getNamespace())
+                                    && ResourceUtils.TYPE_FEATURE.equals(req.getAttributes().get("type"))
+                                    && cond.getCondition().contains(req.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE).toString()));
+                        }
+                        if (ignore) {
+                            getLog().warn("Feature resolution failed for " + ids
+                                    + "\nMessage: " + e.getCause().getMessage());
+                            continue;
+                        }
+                    }
+                    if (e.getCause() instanceof ResolutionException) {
+                        getLog().warn(e.getMessage());
+                    } else {
+                        getLog().warn(e);
+                    }
+                    failures.add(e);
+                    if ("first".equals(fail)) {
+                        throw e;
+                    }
+                }
+            }
+        }
+        if ("end".equals(fail) && !failures.isEmpty()) {
+            throw new MojoExecutionException("Verification failures", new MultiException("Verification failures", failures));
+        }
+    }
+
+    private void verifyResolution(DownloadManager manager, final Map<String, Features> repositories, Set<String> features, Hashtable<String, String> properties) throws MojoExecutionException {
+        try {
+            Bundle systemBundle = getSystemBundle(getMetadata(properties, "metadata#"));
+            DummyDeployCallback callback = new DummyDeployCallback(systemBundle, repositories.values());
+            Deployer deployer = new Deployer(manager, new ResolverImpl(new MavenResolverLog()), callback);
+
+
+            // Install framework
+            Deployer.DeploymentRequest request = createDeploymentRequest();
+
+            for (String fmwk : framework) {
+                MapUtils.addToMapSet(request.requirements, FeaturesService.ROOT_REGION, fmwk);
+            }
+            try {
+                deployer.deploy(callback.getDeploymentState(), request);
+            } catch (Exception e) {
+                throw new MojoExecutionException("Unable to resolve framework features", e);
+            }
+
+
+            /*
+            boolean resolveOptionalImports = getResolveOptionalImports(properties);
+
+            DeploymentBuilder builder = new DeploymentBuilder(
+                    manager,
+                    null,
+                    repositories.values(),
+                    -1 // Disable url handlers
+            );
+            Map<String, Resource> downloadedResources = builder.download(
+                    getPrefixedProperties(properties, "feature."),
+                    getPrefixedProperties(properties, "bundle."),
+                    getPrefixedProperties(properties, "fab."),
+                    getPrefixedProperties(properties, "req."),
+                    getPrefixedProperties(properties, "override."),
+                    getPrefixedProperties(properties, "optional."),
+                    getMetadata(properties, "metadata#")
+            );
+
+            for (String uri : getPrefixedProperties(properties, "resources.")) {
+                builder.addResourceRepository(new MetadataRepository(new HttpMetadataProvider(uri)));
+            }
+            */
+
+
+            // Install features
+            for (String feature : features) {
+                MapUtils.addToMapSet(request.requirements, FeaturesService.ROOT_REGION, feature);
+            }
+            try {
+                Set<String> prereqs = new HashSet<>();
+                while (true) {
+                    try {
+                        deployer.deploy(callback.getDeploymentState(), request);
+                        break;
+                    } catch (Deployer.PartialDeploymentException e) {
+                        if (!prereqs.containsAll(e.getMissing())) {
+                            prereqs.addAll(e.getMissing());
+                        } else {
+                            throw new Exception("Deployment aborted due to loop in missing prerequisites: " + e.getMissing());
+                        }
+                    }
+                }
+                // TODO: find unused resources ?
+            } catch (Exception e) {
+                throw new MojoExecutionException("Feature resolution failed for " + features
+                        + "\nMessage: " + e.getMessage()
+                        + "\nRepositories: " + toString(new TreeSet<>(repositories.keySet()))
+                        + "\nResources: " + toString(new TreeSet<>(manager.getProviders().keySet())), e);
+            }
+
+
+        } catch (MojoExecutionException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new MojoExecutionException("Error verifying feature " + features + "\nMessage: " + e.getMessage(), e);
+        }
+    }
+
+    private Deployer.DeploymentRequest createDeploymentRequest() {
+        Deployer.DeploymentRequest request = new Deployer.DeploymentRequest();
+        request.bundleUpdateRange = FeaturesService.DEFAULT_BUNDLE_UPDATE_RANGE;
+        request.featureResolutionRange = FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE;
+        request.overrides = new HashSet<>();
+        request.requirements = new HashMap<>();
+        request.stateChanges = new HashMap<>();
+        request.options = EnumSet.noneOf(FeaturesService.Option.class);
+        return request;
+    }
+
+    private String toString(Collection<String> collection) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{\n");
+        for (String s : collection) {
+            sb.append("\t").append(s).append("\n");
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+
+    private Bundle getSystemBundle(Map<String, Map<VersionRange, Map<String, String>>> metadata) throws Exception {
+        URL configPropURL;
+        if (configuration != null) {
+            configPropURL = new URL(configuration);
+        } else {
+            Artifact karafDistro = project.getArtifactMap().get(distribution);
+            if (karafDistro == null) {
+                throw new MojoFailureException("The karaf distribution " + distribution + " is not a dependency");
+            }
+            if ("kar".equals(karafDistro.getType()) && distDir == null) {
+                distDir = "resources";
+            }
+            String dir = distDir;
+            if (dir == null) {
+                dir = karafDistro.getArtifactId() + "-" + karafDistro.getBaseVersion();
+            }
+            configPropURL = new URL("jar:file:" + karafDistro.getFile() + "!/" + dir + "/etc/config.properties");
+        }
+        org.apache.felix.utils.properties.Properties configProps = PropertiesLoader.loadPropertiesFile(configPropURL, true);
+//        copySystemProperties(configProps);
+        if (javase == null) {
+            configProps.put("java.specification.version", System.getProperty("java.specification.version"));
+        } else {
+            configProps.put("java.specification.version", javase);
+        }
+        configProps.substitute();
+
+        Attributes attributes = new Attributes();
+        attributes.putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
+        attributes.putValue(Constants.BUNDLE_SYMBOLICNAME, "system.bundle");
+        attributes.putValue(Constants.BUNDLE_VERSION, "0.0.0");
+
+        String exportPackages = configProps.getProperty("org.osgi.framework.system.packages");
+        if (configProps.containsKey("org.osgi.framework.system.packages.extra")) {
+            exportPackages += "," + configProps.getProperty("org.osgi.framework.system.packages.extra");
+        }
+        exportPackages = exportPackages.replaceAll(",\\s*,", ",");
+        attributes.putValue(Constants.EXPORT_PACKAGE, exportPackages);
+
+        String systemCaps = configProps.getProperty("org.osgi.framework.system.capabilities");
+        attributes.putValue(Constants.PROVIDE_CAPABILITY, systemCaps);
+
+        // TODO: support metadata overrides on system bundle
+//        attributes = DeploymentBuilder.overrideAttributes(attributes, metadata);
+
+        final Hashtable<String, String> headers = new Hashtable<>();
+        for (Map.Entry attr : attributes.entrySet()) {
+            headers.put(attr.getKey().toString(), attr.getValue().toString());
+        }
+
+        final FakeBundleRevision resource = new FakeBundleRevision(headers, "system-bundle", 0l);
+        return resource.getBundle();
+    }
+
+
+    public static Map<String, Features> loadRepositories(DownloadManager manager, Set<String> uris) throws Exception {
+        final Map<String, Features> loaded = new HashMap<>();
+        final Downloader downloader = manager.createDownloader();
+        for (String repository : uris) {
+            downloader.download(repository, new DownloadCallback() {
+                @Override
+                public void downloaded(final StreamProvider provider) throws Exception {
+                    try (InputStream is = provider.open()) {
+                        Features featuresModel = JaxbUtil.unmarshal(provider.getUrl(), is, false);
+                        synchronized (loaded) {
+                            loaded.put(provider.getUrl(), featuresModel);
+                            for (String innerRepository : featuresModel.getRepository()) {
+                                downloader.download(innerRepository, this);
+                            }
+                        }
+                    }
+                }
+            });
+        }
+        downloader.await();
+        return loaded;
+    }
+
+    public static Set<String> getPrefixedProperties(Map<String, String> properties, String prefix) {
+        Set<String> result = new HashSet<>();
+        for (String key : properties.keySet()) {
+            if (key.startsWith(prefix)) {
+                String url = properties.get(key);
+                if (url == null || url.length() == 0) {
+                    url = key.substring(prefix.length());
+                }
+                if (!url.isEmpty()) {
+                    result.add(url);
+                }
+            }
+        }
+        return result;
+    }
+
+    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()) {
+            if (key.startsWith(prefix)) {
+                String val = properties.get(key);
+                key = key.substring(prefix.length());
+                String[] parts = key.split("#");
+                if (parts.length == 3) {
+                    Map<VersionRange, Map<String, String>> ranges = result.get(parts[0]);
+                    if (ranges == null) {
+                        ranges = new HashMap<>();
+                        result.put(parts[0], ranges);
+                    }
+                    String version = parts[1];
+                    if (!version.startsWith("[") && !version.startsWith("(")) {
+                        Processor processor = new Processor();
+                        processor.setProperty("@", VersionTable.getVersion(version).toString());
+                        Macro macro = new Macro(processor);
+                        version = macro.process("${range;[==,=+)}");
+                    }
+                    VersionRange range = new VersionRange(version);
+                    Map<String, String> hdrs = ranges.get(range);
+                    if (hdrs == null) {
+                        hdrs = new HashMap<>();
+                        ranges.put(range, hdrs);
+                    }
+                    hdrs.put(parts[2], val);
+                }
+            }
+        }
+        return result;
+    }
+
+    public static class FakeBundleRevision extends ResourceImpl implements BundleRevision, BundleStartLevel {
+
+        private final Bundle bundle;
+        private int startLevel;
+
+        public FakeBundleRevision(final Hashtable<String, String> headers, final String location, final long bundleId) throws BundleException {
+            ResourceBuilder.build(this, location, headers);
+            this.bundle = (Bundle) Proxy.newProxyInstance(
+                    getClass().getClassLoader(),
+                    new Class[] { Bundle.class },
+                    new InvocationHandler() {
+                        @Override
+                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                            if (method.getName().equals("hashCode")) {
+                                return FakeBundleRevision.this.hashCode();
+                            } else if (method.getName().equals("equals")) {
+                                return proxy == args[0];
+                            } else if (method.getName().equals("toString")) {
+                                return bundle.getSymbolicName() + "/" + bundle.getVersion();
+                            } else if (method.getName().equals("adapt")) {
+                                if (args.length == 1 && args[0] == BundleRevision.class) {
+                                    return FakeBundleRevision.this;
+                                } else if (args.length == 1 && args[0] == BundleStartLevel.class) {
+                                    return FakeBundleRevision.this;
+                                }
+                            } else if (method.getName().equals("getHeaders")) {
+                                return headers;
+                            } else if (method.getName().equals("getBundleId")) {
+                                return bundleId;
+                            } else if (method.getName().equals("getLocation")) {
+                                return location;
+                            } else if (method.getName().equals("getSymbolicName")) {
+                                String name = headers.get(Constants.BUNDLE_SYMBOLICNAME);
+                                int idx = name.indexOf(';');
+                                if (idx > 0) {
+                                    name = name.substring(0, idx).trim();
+                                }
+                                return name;
+                            } else if (method.getName().equals("getVersion")) {
+                                return new Version(headers.get(Constants.BUNDLE_VERSION));
+                            } else if (method.getName().equals("getState")) {
+                                return Bundle.ACTIVE;
+                            } else if (method.getName().equals("getLastModified")) {
+                                return 0l;
+                            }
+                            return null;
+                        }
+                    });
+        }
+
+        @Override
+        public int getStartLevel() {
+            return startLevel;
+        }
+
+        @Override
+        public void setStartLevel(int startLevel) {
+            this.startLevel = startLevel;
+        }
+
+        @Override
+        public boolean isPersistentlyStarted() {
+            return true;
+        }
+
+        @Override
+        public boolean isActivationPolicyUsed() {
+            return false;
+        }
+
+        @Override
+        public String getSymbolicName() {
+            return bundle.getSymbolicName();
+        }
+
+        @Override
+        public Version getVersion() {
+            return bundle.getVersion();
+        }
+
+        @Override
+        public List<BundleCapability> getDeclaredCapabilities(String namespace) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public List<BundleRequirement> getDeclaredRequirements(String namespace) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int getTypes() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public BundleWiring getWiring() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle getBundle() {
+            return bundle;
+        }
+    }
+
+    public static class DummyDeployCallback implements Deployer.DeployCallback {
+
+        private final Bundle systemBundle;
+        private final Deployer.DeploymentState dstate;
+        private final AtomicLong nextBundleId = new AtomicLong(0);
+
+        public DummyDeployCallback(Bundle sysBundle, Collection<Features> repositories) throws Exception {
+            systemBundle = sysBundle;
+            dstate = new Deployer.DeploymentState();
+            dstate.bundles = new HashMap<>();
+            dstate.features = new HashMap<>();
+            dstate.bundlesPerRegion = new HashMap<>();
+            dstate.filtersPerRegion = new HashMap<>();
+            dstate.state = new State();
+
+            MapUtils.addToMapSet(dstate.bundlesPerRegion, FeaturesService.ROOT_REGION, 0l);
+            dstate.bundles.put(0l, systemBundle);
+            for (Features repo : repositories) {
+                for (Feature f : repo.getFeature()) {
+                    dstate.features.put(f.getId(), f);
+                }
+            }
+        }
+
+        public Deployer.DeploymentState getDeploymentState() {
+            return dstate;
+        }
+
+        @Override
+        public void print(String message, boolean verbose) {
+        }
+
+        @Override
+        public void saveState(State state) {
+            dstate.state.replace(state);
+        }
+
+        @Override
+        public void persistResolveRequest(Deployer.DeploymentRequest request) throws IOException {
+        }
+
+        @Override
+        public void installFeature(org.apache.karaf.features.Feature feature) throws IOException, InvalidSyntaxException {
+        }
+
+        @Override
+        public void callListeners(FeatureEvent featureEvent) {
+        }
+
+        @Override
+        public Bundle installBundle(String region, String uri, InputStream is) throws BundleException {
+            try {
+                Hashtable<String, String> headers = new Hashtable<>();
+                ZipInputStream zis = new ZipInputStream(is);
+                ZipEntry entry;
+                while ((entry = zis.getNextEntry()) != null) {
+                    if (MANIFEST_NAME.equals(entry.getName())) {
+                        Attributes attributes = new Manifest(zis).getMainAttributes();
+                        for (Map.Entry attr : attributes.entrySet()) {
+                            headers.put(attr.getKey().toString(), attr.getValue().toString());
+                        }
+                    }
+                }
+                BundleRevision revision = new FakeBundleRevision(headers, uri, nextBundleId.incrementAndGet());
+                Bundle bundle = revision.getBundle();
+                MapUtils.addToMapSet(dstate.bundlesPerRegion, region, bundle.getBundleId());
+                dstate.bundles.put(bundle.getBundleId(), bundle);
+                return bundle;
+            } catch (IOException e) {
+                throw new BundleException("Unable to install bundle", e);
+            }
+        }
+
+        @Override
+        public void updateBundle(Bundle bundle, String uri, InputStream is) throws BundleException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void uninstall(Bundle bundle) throws BundleException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void startBundle(Bundle bundle) throws BundleException {
+        }
+
+        @Override
+        public void stopBundle(Bundle bundle, int options) throws BundleException {
+        }
+
+        @Override
+        public void setBundleStartLevel(Bundle bundle, int startLevel) {
+        }
+
+        @Override
+        public void refreshPackages(Collection<Bundle> bundles) throws InterruptedException {
+        }
+
+        @Override
+        public void resolveBundles(Set<Bundle> bundles, Map<Resource, List<Wire>> wiring, Map<Resource, Bundle> resToBnd) {
+        }
+
+        @Override
+        public void replaceDigraph(Map<String, Map<String, Map<String, Set<String>>>> policies, Map<String, Set<Long>> bundles) throws BundleException, InvalidSyntaxException {
+        }
+    }
+
+    public class MavenResolverLog extends org.apache.felix.resolver.Logger {
+
+        public MavenResolverLog() {
+            super(Logger.LOG_DEBUG);
+        }
+
+        @Override
+        protected void doLog(int level, String msg, Throwable throwable) {
+            switch (level) {
+            case LOG_DEBUG:
+                getLog().debug(msg, throwable);
+                break;
+            case LOG_INFO:
+                getLog().info(msg, throwable);
+                break;
+            case LOG_WARNING:
+                getLog().warn(msg, throwable);
+                break;
+            case LOG_ERROR:
+                getLog().error(msg, throwable);
+                break;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/056239dc/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AbstractFeatureMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AbstractFeatureMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AbstractFeatureMojo.java
index 0173e62..d2af3e6 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AbstractFeatureMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AbstractFeatureMojo.java
@@ -42,7 +42,7 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.osgi.framework.Version;
 
 /**
- * Common functionality for mojos that need to reolve features
+ * Common functionality for mojos that need to resolve features
  */
 public abstract class AbstractFeatureMojo extends MojoSupport {
     

http://git-wip-us.apache.org/repos/asf/karaf/blob/056239dc/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AddToRepositoryMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AddToRepositoryMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AddToRepositoryMojo.java
index ba5eae0..7290695 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AddToRepositoryMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/AddToRepositoryMojo.java
@@ -28,18 +28,15 @@ import org.apache.karaf.tooling.utils.MavenUtil;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
+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;
 
 /**
  * Add features to a repository directory
- *
- * @goal features-add-to-repository
- * @phase compile
- * @execute phase="compile"
- * @requiresDependencyResolution runtime
- * @inheritByDefault true
- * @description Add the features to the repository
  */
+@Mojo(name = "features-add-to-repository", defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.RUNTIME)
 public class AddToRepositoryMojo extends AbstractFeatureMojo {
 
     @Parameter(defaultValue = "${project.build.directory}/features-repo")

http://git-wip-us.apache.org/repos/asf/karaf/blob/056239dc/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
deleted file mode 100644
index 6bd447a..0000000
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * 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.features;
-
-import java.io.*;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.karaf.deployer.kar.KarArtifactInstaller;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.ConfigFileInfo;
-import org.apache.karaf.features.internal.model.Feature;
-import org.apache.karaf.features.internal.model.Features;
-import org.apache.karaf.features.internal.model.JaxbUtil;
-import org.apache.karaf.tooling.utils.MavenUtil;
-import org.apache.karaf.tooling.utils.MojoSupport;
-import org.apache.maven.archiver.MavenArchiveConfiguration;
-import org.apache.maven.archiver.MavenArchiver;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
-import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
-import org.apache.maven.artifact.repository.metadata.Metadata;
-import org.apache.maven.artifact.repository.metadata.Snapshot;
-import org.apache.maven.artifact.repository.metadata.SnapshotVersion;
-import org.apache.maven.artifact.repository.metadata.Versioning;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
-import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugins.annotations.Component;
-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.codehaus.plexus.archiver.Archiver;
-import org.codehaus.plexus.archiver.jar.JarArchiver;
-
-/**
- * Assemble a kar archive from a features.xml file
- */
-@Mojo(name = "features-create-kar", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.RUNTIME)
-public class CreateKarMojo extends MojoSupport {
-
-    /**
-     * The maven archive configuration to use.
-     * <p/>
-     * See <a href="http://maven.apache.org/ref/current/maven-archiver/apidocs/org/apache/maven/archiver/MavenArchiveConfiguration.html">the Javadocs for MavenArchiveConfiguration</a>.
-     */
-    @Parameter
-    private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
-
-    /**
-     * The Jar archiver.
-     */
-    @Component(role = Archiver.class, hint="jar")
-    private JarArchiver jarArchiver = null;
-
-    /**
-     * Directory containing the generated archive.
-     */
-    @Parameter(defaultValue = "${project.build.directory}")
-    private File outputDirectory = null;
-
-    /**
-     * Name of the generated archive.
-     */
-    @Parameter(defaultValue = "${project.build.finalName}")
-    private String finalName = null;
-
-    /**
-     * Ignore the dependency flag on the bundles in the features XML
-     */
-    @Parameter(defaultValue = "false")
-    private boolean ignoreDependencyFlag;
-
-    /**
-     * Classifier to add to the artifact generated. If given, the artifact will be attached.
-     * If it's not given, it will merely be written to the output directory according to the finalName.
-     */
-    @Parameter
-    protected String classifier;
-
-    /**
-     * Location of resources directory for additional content to include in the kar.
-     * Note that it includes everything under classes so as to include maven-remote-resources
-     */
-    @Parameter(defaultValue = "${project.build.directory}/classes")
-    private File resourcesDir;
-
-
-    /**
-     * The features file to use as instructions
-     */
-    @Parameter(defaultValue = "${project.build.directory}/feature/feature.xml")
-    private String featuresFile;
-
-
-    /**
-     * The wrapper repository in the kar.
-     */
-    @Parameter(defaultValue = "${repositoryPath}")
-    private String repositoryPath = "repository/";
-
-    private static final Pattern mvnPattern = Pattern.compile("mvn:([^/ ]+)/([^/ ]+)/([^/ ]*)(/([^/ ]+)(/([^/ ]+))?)?");
-
-
-    //
-    // Mojo
-    //
-
-    public void execute() throws MojoExecutionException, MojoFailureException {
-        File featuresFileResolved = resolveFile(featuresFile);
-        String groupId = project.getGroupId();
-        String artifactId = project.getArtifactId();
-        String version = project.getVersion();
-
-        if (isMavenUrl(featuresFile)) {
-            Artifact artifactTemp = resourceToArtifact(featuresFile, false);
-            if (artifactTemp.getGroupId() != null)
-                groupId = artifactTemp.getGroupId();
-            if (artifactTemp.getArtifactHandler() != null)
-                artifactId = artifactTemp.getArtifactId();
-            if (artifactTemp.getVersion() != null)
-                version = artifactTemp.getVersion();
-        }
-
-        List<Artifact> resources = readResources(featuresFileResolved);
-
-        // Build the archive
-        File archive = createArchive(resources, featuresFileResolved, groupId, artifactId, version);
-
-        // if no classifier is specified and packaging is not kar, display a warning
-        // and attach artifact
-        if (classifier == null && !this.getProject().getPackaging().equals("kar")) {
-            this.getLog().warn("Your project should use the \"kar\" packaging or configure a \"classifier\" for kar attachment");
-            projectHelper.attachArtifact(getProject(), "kar", null, archive);
-            return;
-        }
-
-        // Attach the generated archive for install/deploy
-        if (classifier != null) {
-            projectHelper.attachArtifact(getProject(), "kar", classifier, archive);
-        } else {
-            getProject().getArtifact().setFile(archive);
-        }
-    }
-
-    private File resolveFile(String file) {
-        File fileResolved = null;
-
-        if (isMavenUrl(file)) {
-            fileResolved = new File(fromMaven(file));
-            try {
-                Artifact artifactTemp = resourceToArtifact(file, false);
-                if (!fileResolved.exists()) {
-                    try {
-                        artifactResolver.resolve(artifactTemp, remoteRepos, localRepo);
-                        fileResolved = artifactTemp.getFile();
-                    } catch (ArtifactResolutionException e) {
-                        getLog().error("Artifact was not resolved", e);
-                    } catch (ArtifactNotFoundException e) {
-                        getLog().error("Artifact was not found", e);
-                    }
-                }
-            } catch (MojoExecutionException e) {
-                getLog().error(e);
-            }
-        } else {
-            fileResolved = new File(file);
-        }
-
-        return fileResolved;
-    }
-
-    /**
-     * Read bundles and configuration files in the features file.
-     *
-     * @return
-     * @throws MojoExecutionException
-     */
-    private List<Artifact> readResources(File featuresFile) throws MojoExecutionException {
-        List<Artifact> resources = new ArrayList<Artifact>();
-        try {
-            Features features = JaxbUtil.unmarshal(featuresFile.toURI().toASCIIString(), false);
-            for (Feature feature : features.getFeature()) {
-                for (BundleInfo bundle : feature.getBundles()) {
-                    if (ignoreDependencyFlag || (!ignoreDependencyFlag && !bundle.isDependency())) {
-                        resources.add(resourceToArtifact(bundle.getLocation(), false));
-                    }
-                }
-                for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
-                    resources.add(resourceToArtifact(configFile.getLocation(), false));
-                }
-            }
-            return resources;
-        } catch (MojoExecutionException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new MojoExecutionException("Could not interpret features.xml", e);
-        }
-    }
-
-    /**
-     * Generates the configuration archive.
-     *
-     * @param bundles
-     */
-    @SuppressWarnings("deprecation")
-	private File createArchive(List<Artifact> bundles, File featuresFile, String groupId, String artifactId, String version) throws MojoExecutionException {
-        ArtifactRepositoryLayout layout = new DefaultRepositoryLayout();
-        File archiveFile = getArchiveFile(outputDirectory, finalName, classifier);
-
-        MavenArchiver archiver = new MavenArchiver();
-        archiver.setArchiver(jarArchiver);
-        archiver.setOutputFile(archiveFile);
-
-        try {
-            //TODO should .kar be a bundle?
-//            archive.addManifestEntry(Constants.BUNDLE_NAME, project.getName());
-//            archive.addManifestEntry(Constants.BUNDLE_VENDOR, project.getOrganization().getName());
-//            ArtifactVersion version = project.getArtifact().getSelectedVersion();
-//            String versionString = "" + version.getMajorVersion() + "." + version.getMinorVersion() + "." + version.getIncrementalVersion();
-//            if (version.getQualifier() != null) {
-//                versionString += "." + version.getQualifier();
-//            }
-//            archive.addManifestEntry(Constants.BUNDLE_VERSION, versionString);
-//            archive.addManifestEntry(Constants.BUNDLE_MANIFESTVERSION, "2");
-//            archive.addManifestEntry(Constants.BUNDLE_DESCRIPTION, project.getDescription());
-//            // NB, no constant for this one
-//            archive.addManifestEntry("Bundle-License", ((License) project.getLicenses().get(0)).getUrl());
-//            archive.addManifestEntry(Constants.BUNDLE_DOCURL, project.getUrl());
-//            //TODO this might need some help
-//            archive.addManifestEntry(Constants.BUNDLE_SYMBOLICNAME, project.getArtifactId());
-
-            //include the feature.xml
-			Artifact featureArtifact = factory.createArtifactWithClassifier(groupId, artifactId, version, "xml", KarArtifactInstaller.FEATURE_CLASSIFIER);
-            jarArchiver.addFile(featuresFile, repositoryPath + layout.pathOf(featureArtifact));
-
-            if (featureArtifact.isSnapshot()) {
-                // the artifact is a snapshot, create the maven-metadata-local.xml
-                getLog().debug("Feature artifact is a SNAPSHOT, handling the maven-metadata-local.xml");
-                File metadataTarget = new File(featuresFile.getParentFile(), "maven-metadata-local.xml");
-                getLog().debug("Looking for " + metadataTarget.getAbsolutePath());
-                if (!metadataTarget.exists()) {
-                    // the maven-metadata-local.xml doesn't exist, create it
-                    getLog().debug(metadataTarget.getAbsolutePath() + " doesn't exist, create it");
-                    Metadata metadata = new Metadata();
-                    metadata.setGroupId(featureArtifact.getGroupId());
-                    metadata.setArtifactId(featureArtifact.getArtifactId());
-                    metadata.setVersion(featureArtifact.getVersion());
-                    metadata.setModelVersion("1.1.0");
-
-                    Versioning versioning = new Versioning();
-                    versioning.setLastUpdatedTimestamp(new Date(System.currentTimeMillis()));
-                    Snapshot snapshot = new Snapshot();
-                    snapshot.setLocalCopy(true);
-                    versioning.setSnapshot(snapshot);
-                    SnapshotVersion snapshotVersion = new SnapshotVersion();
-                    snapshotVersion.setClassifier(featureArtifact.getClassifier());
-                    snapshotVersion.setVersion(featureArtifact.getVersion());
-                    snapshotVersion.setExtension(featureArtifact.getType());
-                    snapshotVersion.setUpdated(versioning.getLastUpdated());
-                    versioning.addSnapshotVersion(snapshotVersion);
-
-                    metadata.setVersioning(versioning);
-
-                    MetadataXpp3Writer metadataWriter = new MetadataXpp3Writer();
-                    try {
-                        Writer writer = new FileWriter(metadataTarget);
-                        metadataWriter.write(writer, metadata);
-                    } 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");
-                    }
-                }
-                getLog().debug("Adding file " + metadataTarget.getAbsolutePath() + " in the jar path " + repositoryPath + layout.pathOf(featureArtifact).substring(0, layout.pathOf(featureArtifact).lastIndexOf('/')) + "/maven-metadata-local.xml");
-                jarArchiver.addFile(metadataTarget, repositoryPath + layout.pathOf(featureArtifact).substring(0, layout.pathOf(featureArtifact).lastIndexOf('/')) + "/maven-metadata-local.xml");
-            }
-
-            for (Artifact artifact : bundles) {
-                artifactResolver.resolve(artifact, remoteRepos, localRepo);
-                File localFile = artifact.getFile();
-
-                if (artifact.isSnapshot()) {
-                    // the artifact is a snapshot, create the maven-metadata-local.xml
-                    File metadataTarget = new File(localFile.getParentFile(), "maven-metadata-local.xml");
-                    if (!metadataTarget.exists()) {
-                        // the maven-metadata-local.xml doesn't exist, create it
-                        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");
-                        }
-                    }
-                    jarArchiver.addFile(metadataTarget, repositoryPath + layout.pathOf(artifact).substring(0, layout.pathOf(artifact).lastIndexOf('/')) + "/maven-metadata-local.xml");
-                }
-
-                //TODO this may not be reasonable, but... resolved snapshot artifacts have timestamped versions
-                //which do not work in startup.properties.
-                artifact.setVersion(artifact.getBaseVersion());
-                String targetFileName = repositoryPath + layout.pathOf(artifact);
-                jarArchiver.addFile(localFile, targetFileName);
-            }
-
-            if (resourcesDir.isDirectory()) {
-                archiver.getArchiver().addDirectory(resourcesDir);
-            }
-            archiver.createArchive(project, archive);
-
-            return archiveFile;
-        } catch (Exception e) {
-            throw new MojoExecutionException("Failed to create archive", e);
-        }
-    }
-
-    protected static boolean isMavenUrl(String name) {
-        Matcher m = mvnPattern.matcher(name);
-        return m.matches();
-    }
-
-    /**
-     * Return a path for an artifact:
-     * - if the input is already a path (doesn't contain ':'), the same path is returned.
-     * - if the input is a Maven URL, the input is converted to a default repository location path, type and classifier
-     *   are optional.
-     *
-     * @param name artifact data
-     * @return path as supplied or a default Maven repository path
-     */
-    private static String fromMaven(String name) {
-        Matcher m = mvnPattern.matcher(name);
-        if (!m.matches()) {
-            return name;
-        }
-
-        StringBuilder b = new StringBuilder();
-        b.append(m.group(1));
-        for (int i = 0; i < b.length(); i++) {
-            if (b.charAt(i) == '.') {
-                b.setCharAt(i, '/');
-            }
-        }
-        b.append("/"); // groupId
-        String artifactId = m.group(2);
-        String version = m.group(3);
-        String extension = m.group(5);
-        String classifier = m.group(7);
-        b.append(artifactId).append("/"); // artifactId
-        b.append(version).append("/"); // version
-        b.append(artifactId).append("-").append(version);
-        if (present(classifier)) {
-            b.append("-").append(classifier);
-        }
-        if (present(classifier)) {
-            b.append(".").append(extension);
-        } else {
-            b.append(".jar");
-        }
-        return b.toString();
-    }
-
-    private static boolean present(String part) {
-        return part != null && !part.isEmpty();
-    }
-
-    protected static File getArchiveFile(final File basedir, final String finalName, String classifier) {
-        if (classifier == null) {
-            classifier = "";
-        } else if (classifier.trim().length() > 0 && !classifier.startsWith("-")) {
-            classifier = "-" + classifier;
-        }
-
-        return new File(basedir, finalName + classifier + ".kar");
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/056239dc/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
deleted file mode 100644
index 47ae0a9..0000000
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * 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.features;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.karaf.profile.assembly.Builder;
-import org.apache.karaf.tooling.utils.DependencyHelper;
-import org.apache.karaf.tooling.utils.DependencyHelperFactory;
-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;
-import org.apache.maven.plugin.MojoFailureException;
-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;
-
-/**
- * Installs kar dependencies into a server-under-construction in target/assembly
- */
-@Mojo(name = "install-kars", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, requiresDependencyResolution = ResolutionScope.RUNTIME)
-public class InstallKarsMojo extends MojoSupport {
-
-    /**
-     * Base directory used to copy the resources during the build (working directory).
-     */
-    @Parameter(defaultValue = "${project.build.directory}/assembly")
-    protected File workDirectory;
-
-    /**
-     * Features configuration file (etc/org.apache.karaf.features.cfg).
-     */
-    @Parameter(defaultValue = "${project.build.directory}/assembly/etc/org.apache.karaf.features.cfg")
-    protected File featuresCfgFile;
-
-    /**
-     * startup.properties file.
-     */
-    @Parameter(defaultValue = "${project.build.directory}/assembly/etc/startup.properties")
-    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;
-
-    @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.
-     */
-    @Parameter
-    private List<String> startupFeatures;
-
-    /**
-     * List of features from runtime-scope features xml and kars to be installed into system repo and listed in features service boot features.
-     */
-    @Parameter
-    private List<String> bootFeatures;
-
-    /**
-     * List of features from runtime-scope features xml and kars to be installed into system repo and not mentioned elsewhere.
-     */
-    @Parameter
-    private List<String> installedFeatures;
-
-    @Parameter
-    private List<String> blacklistedFeatures;
-
-    @Parameter
-    private List<String> startupBundles;
-    @Parameter
-    private List<String> bootBundles;
-    @Parameter
-    private List<String> installedBundles;
-    @Parameter
-    private List<String> blacklistedBundles;
-    
-    @Parameter
-    private String profilesUri;
-
-    @Parameter
-    private List<String> bootProfiles;
-
-    @Parameter
-    private List<String> startupProfiles;
-
-    @Parameter
-    private List<String> installedProfiles;
-
-    @Parameter
-    private List<String> blacklistedProfiles;
-
-    @Parameter
-    private Builder.BlacklistPolicy blacklistPolicy;
-
-    /**
-     * Ignore the dependency attribute (dependency="[true|false]") on bundle
-     */
-    @Parameter(defaultValue = "false")
-    protected boolean ignoreDependencyFlag;
-
-    /**
-     * Additional feature repositories
-     */
-    @Parameter
-    protected List<String> featureRepositories;
-
-    @Parameter
-    protected List<String> libraries;
-
-    /**
-     * Use reference: style urls in startup.properties
-     */
-    @Parameter(defaultValue = "false")
-    protected boolean useReferenceUrls;
-
-    @Parameter
-    protected boolean installAllFeaturesByDefault = true;
-
-    @Parameter
-    protected Builder.KarafVersion karafVersion = Builder.KarafVersion.v4x;
-
-    // an access layer for available Aether implementation
-    protected DependencyHelper dependencyHelper;
-
-    @Override
-    public void execute() throws MojoExecutionException, MojoFailureException {
-        this.dependencyHelper = DependencyHelperFactory.createDependencyHelper(this.container, this.project, this.mavenSession, getLog());
-        try {
-            doExecute();
-        }
-        catch (MojoExecutionException | MojoFailureException e) {
-            throw e;
-        }
-        catch (Exception e) {
-            throw new MojoExecutionException("Unable to build assembly", e);
-        }
-    }
-
-    protected void doExecute() throws Exception {
-        startupRepositories = nonNullList(startupRepositories);
-        bootRepositories = nonNullList(bootRepositories);
-        installedRepositories = nonNullList(installedRepositories);
-        startupBundles = nonNullList(startupBundles);
-        bootBundles = nonNullList(bootBundles);
-        installedBundles = nonNullList(installedBundles);
-        blacklistedBundles = nonNullList(blacklistedBundles);
-        startupFeatures = nonNullList(startupFeatures);
-        bootFeatures = nonNullList(bootFeatures);
-        installedFeatures = nonNullList(installedFeatures);
-        blacklistedFeatures = nonNullList(blacklistedFeatures);
-        startupProfiles = nonNullList(startupProfiles);
-        bootProfiles = nonNullList(bootProfiles);
-        installedProfiles = nonNullList(installedProfiles);
-        blacklistedProfiles = nonNullList(blacklistedProfiles);
-
-        if (!startupProfiles.isEmpty() || !bootProfiles.isEmpty() || !installedProfiles.isEmpty()) {
-            if (profilesUri == null) {
-                throw new IllegalArgumentException("profilesDirectory must be specified");
-            }
-        }
-
-        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);
-        }
-
-        Builder builder = Builder.newInstance();
-
-        // Set up blacklisted items
-        builder.blacklistBundles(blacklistedBundles);
-        builder.blacklistFeatures(blacklistedFeatures);
-        builder.blacklistProfiles(blacklistedProfiles);
-        builder.blacklistPolicy(blacklistPolicy);
-
-        // creating system directory
-        getLog().info("Creating work directory");
-        builder.homeDirectory(workDirectory.toPath());
-        IoUtils.deleteRecursive(workDirectory);
-        workDirectory.mkdirs();
-
-        List<String> startupKars = new ArrayList<>();
-        List<String> bootKars = new ArrayList<>();
-        List<String> installedKars = new ArrayList<>();
-
-        // Loading kars and features repositories
-        getLog().info("Loading kar and features repositories dependencies");
-        for (Artifact artifact : project.getDependencyArtifacts()) {
-            Builder.Stage stage;
-            switch (artifact.getScope()) {
-            case "compile":
-                stage = Builder.Stage.Startup;
-                break;
-            case "runtime":
-                stage = Builder.Stage.Boot;
-                break;
-            case "provided":
-                stage = Builder.Stage.Installed;
-                break;
-            default:
-                continue;
-            }
-            if ("kar".equals(artifact.getType())) {
-                String uri = dependencyHelper.artifactToMvn(artifact);
-                switch (stage) {
-                case Startup:   startupKars.add(uri); break;
-                case Boot:      bootKars.add(uri); break;
-                case Installed: installedKars.add(uri); break;
-                }
-            } else if ("features".equals(artifact.getClassifier())) {
-                String uri = dependencyHelper.artifactToMvn(artifact);
-                switch (stage) {
-                case Startup:   startupRepositories.add(uri); break;
-                case Boot:      bootRepositories.add(uri); break;
-                case Installed: installedRepositories.add(uri); break;
-                }
-            } else if ("jar".equals(artifact.getType()) || "bundle".equals(artifact.getType())) {
-                String uri = dependencyHelper.artifactToMvn(artifact);
-                switch (stage) {
-                case Startup:   startupBundles.add(uri); break;
-                case Boot:      bootBundles.add(uri); break;
-                case Installed: installedBundles.add(uri); break;
-                }
-            }
-        }
-
-        builder.karafVersion(karafVersion)
-               .useReferenceUrls(useReferenceUrls)
-               .defaultAddAll(installAllFeaturesByDefault)
-               .ignoreDependencyFlag(ignoreDependencyFlag);
-        if (profilesUri != null) {
-            builder.profilesUris(profilesUri);
-        }
-        if (libraries != null) {
-            builder.libraries(libraries.toArray(new String[libraries.size()]));
-        }
-        // Startup
-        builder.defaultStage(Builder.Stage.Startup)
-               .kars(toArray(startupKars))
-               .repositories(startupFeatures.isEmpty() && startupProfiles.isEmpty() && installAllFeaturesByDefault, toArray(startupRepositories))
-               .features(toArray(startupFeatures))
-               .bundles(toArray(startupBundles))
-               .profiles(toArray(startupProfiles));
-        // Boot
-        builder.defaultStage(Builder.Stage.Boot)
-                .kars(toArray(bootKars))
-                .repositories(bootFeatures.isEmpty() && bootProfiles.isEmpty() && installAllFeaturesByDefault, toArray(bootRepositories))
-                .features(toArray(bootFeatures))
-                .bundles(toArray(bootBundles))
-                .profiles(toArray(bootProfiles));
-        // Installed
-        builder.defaultStage(Builder.Stage.Installed)
-                .kars(toArray(installedKars))
-                .repositories(installedFeatures.isEmpty() && installedProfiles.isEmpty() && installAllFeaturesByDefault, toArray(installedRepositories))
-                .features(toArray(installedFeatures))
-                .bundles(toArray(installedBundles))
-                .profiles(toArray(installedProfiles));
-
-        builder.generateAssembly();
-    }
-
-    private String[] toArray(List<String> strings) {
-        return strings.toArray(new String[strings.size()]);
-    }
-
-    private List<String> nonNullList(List<String> list) {
-        return list == null ? new ArrayList<String>() : list;
-    }
-
-}