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/10 15:44:26 UTC

[2/5] karaf git commit: Small cleanup of karaf-maven-plugin code

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ResolutionListenerImpl.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ResolutionListenerImpl.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ResolutionListenerImpl.java
deleted file mode 100644
index e0551cb..0000000
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ResolutionListenerImpl.java
+++ /dev/null
@@ -1,157 +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.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Stack;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.resolver.ResolutionListener;
-import org.apache.maven.artifact.versioning.VersionRange;
-import org.apache.maven.plugin.logging.Log;
-
-public class ResolutionListenerImpl implements ResolutionListener {
-    private Stack<Node> parents = new Stack<Node>();
-    private Map<String, Node> artifacts = new HashMap<String, Node>();
-    private Node rootNode;
-    private Log log;
-
-    public void setLog(Log log) {
-        this.log = log;
-    }
-
-    public Log getLog() {
-        return log;
-    }
-
-    public void testArtifact(Artifact artifact) {
-        // getLog().debug("testArtifact: " + artifact);
-        // intentionally blank
-    }
-
-    public void startProcessChildren(Artifact artifact) {
-        // getLog().debug("startProcessChildren: " + artifact);
-        Node node = (Node) artifacts.get(artifact.getDependencyConflictId());
-        if (parents.isEmpty()) {
-            rootNode = node;
-        }
-        parents.push(node);
-    }
-
-    public void endProcessChildren(Artifact artifact) {
-        // getLog().debug("endProcessChildren: " + artifact);
-        Node check = (Node) parents.pop();
-        assert artifact.equals(check.getArtifact());
-    }
-
-    public void omitForNearer(Artifact omitted, Artifact kept) {
-        // getLog().debug("omitForNearer: omitted=" + omitted + ", kept=" +
-        // kept);
-        assert omitted.getDependencyConflictId().equals(
-                kept.getDependencyConflictId());
-        Node node = (Node) artifacts.get(omitted.getDependencyConflictId());
-        assert node != null;
-        node.setArtifact(kept);
-    }
-
-    public void omitForCycle(Artifact artifact) {
-        // getLog().debug("omitForCycle: " + artifact);
-        // intentionally blank
-    }
-
-    public void includeArtifact(Artifact artifact) {
-        // getLog().debug("includeArtifact: " + artifact);
-        Node node = (Node) artifacts.get(artifact.getDependencyConflictId());
-        if (node == null) {
-            node = new Node();
-            artifacts.put(artifact.getDependencyConflictId(), node);
-        }
-        node.setArtifact(artifact);
-        if (!parents.isEmpty()) {
-            Node parent = (Node) parents.peek();
-            parent.getChildren().add(node);
-            node.getParents().add(parent);
-        }
-        if (rootNode != null) {
-            // print(rootNode, "");
-        }
-    }
-
-    protected void print(Node node, String string) {
-        // getLog().debug(string + rootNode.getArtifact());
-        for (Iterator<Node> iter = node.getChildren().iterator(); iter.hasNext();) {
-            Node n = iter.next();
-            print(n, string + "  ");
-        }
-    }
-
-    public void updateScope(Artifact artifact, String scope) {
-        // getLog().debug("updateScope: " + artifact);
-        Node node = (Node) artifacts.get(artifact.getDependencyConflictId());
-
-        node.getArtifact().setScope(scope);
-    }
-
-    public void manageArtifact(Artifact artifact, Artifact replacement) {
-        // getLog().debug("manageArtifact: artifact=" + artifact + ",
-        // replacement=" + replacement);
-        Node node = (Node) artifacts.get(artifact.getDependencyConflictId());
-        if (node != null) {
-            if (replacement.getVersion() != null) {
-                node.getArtifact().setVersion(replacement.getVersion());
-            }
-            if (replacement.getScope() != null) {
-                node.getArtifact().setScope(replacement.getScope());
-            }
-        }
-    }
-
-    public void updateScopeCurrentPom(Artifact artifact, String key) {
-
-        getLog().debug("updateScopeCurrentPom: " + artifact);
-        // intentionally blank
-    }
-
-    public void selectVersionFromRange(Artifact artifact) {
-
-        getLog().debug("selectVersionFromRange: " + artifact);
-        // intentionally blank
-    }
-
-    public void restrictRange(Artifact artifact, Artifact artifact1,
-            VersionRange versionRange) {
-
-        getLog().debug("restrictRange: " + artifact);
-        // intentionally blank
-    }
-
-    public Node getNode(Artifact artifact) {
-        return (Node) artifacts.get(artifact.getDependencyConflictId());
-    }
-
-    public Collection<Node> getArtifacts() {
-        return artifacts.values();
-    }
-
-    public Node getRootNode() {
-        return rootNode;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ValidateDescriptorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ValidateDescriptorMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ValidateDescriptorMojo.java
index f4e22e2..d87597c 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ValidateDescriptorMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ValidateDescriptorMojo.java
@@ -26,6 +26,7 @@ import org.apache.karaf.features.Repository;
 import org.apache.karaf.features.internal.service.FeatureValidationUtil;
 import org.apache.karaf.features.internal.service.RepositoryImpl;
 import org.apache.karaf.tooling.url.CustomBundleURLStreamHandlerFactory;
+import org.apache.karaf.tooling.utils.ManifestUtils;
 import org.apache.karaf.tooling.utils.MojoSupport;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
@@ -55,7 +56,7 @@ import java.util.jar.Manifest;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
-import static org.apache.karaf.tooling.features.ManifestUtils.*;
+import static org.apache.karaf.tooling.utils.ManifestUtils.*;
 
 /**
  * Validates a features XML file

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/ArtifactRef.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/ArtifactRef.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/ArtifactRef.java
deleted file mode 100644
index 53ca9cf..0000000
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/ArtifactRef.java
+++ /dev/null
@@ -1,42 +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.model;
-
-import org.apache.maven.artifact.Artifact;
-
-public class ArtifactRef {
-    String url;
-    Artifact artifact;
-    
-    public ArtifactRef(String url) {
-        super();
-        this.url = url;
-    }
-    
-    public String getUrl() {
-        return url;
-    }
-    
-    public Artifact getArtifact() {
-        return artifact;
-    }
-
-    public void setArtifact(Artifact artifact) {
-        this.artifact = artifact;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/BundleRef.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/BundleRef.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/BundleRef.java
deleted file mode 100644
index ce22648..0000000
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/BundleRef.java
+++ /dev/null
@@ -1,61 +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.model;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.util.jar.JarInputStream;
-import java.util.jar.Manifest;
-
-public class BundleRef extends ArtifactRef {
-    Integer startLevel;
-    String bundleSymbolicName;
-    String bundleVersion;
-
-    public BundleRef(String url, Integer startLevel) {
-        super(url);
-        this.startLevel = startLevel;
-    }
-
-    public Integer getStartLevel() {
-        return startLevel;
-    }
-
-    public void readManifest() {
-        JarInputStream bundleJar = null;
-        try {
-            File file = artifact.getFile();
-            bundleJar = new JarInputStream(new FileInputStream(file));
-            Manifest manifest = bundleJar.getManifest();
-            bundleSymbolicName = manifest.getMainAttributes().getValue("Bundle-SymbolicName");
-            bundleVersion = manifest.getMainAttributes().getValue("Bundle-Version");
-            bundleJar.close();
-        } catch (Exception e) {
-            // Ignore errors in manifest
-        }
-    }
-
-    public String getBundleSymbolicName() {
-        return bundleSymbolicName;
-    }
-
-    public String getBundleVersion() {
-        return bundleVersion;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/ConfigRef.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/ConfigRef.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/ConfigRef.java
deleted file mode 100644
index 26b8808..0000000
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/ConfigRef.java
+++ /dev/null
@@ -1,56 +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.model;
-
-import java.util.Map;
-
-public class ConfigRef {
-
-	private String name;
-	private Map<String, String> properties;
-	private boolean append;
-
-	public ConfigRef(String name, Map<String, String> hashtable, String append) {
-		this.name = name;
-		this.properties = hashtable;
-		this.append = Boolean.parseBoolean(append);
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	public Map<String, String> getProperties() {
-		return properties;
-	}
-
-	public void setProperties(Map<String, String> properties) {
-		this.properties = properties;
-	}
-
-	public boolean isAppend() {
-		return append;
-	}
-
-	public void setAppend(boolean append) {
-		this.append = append;
-	}
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/Feature.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/Feature.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/Feature.java
deleted file mode 100644
index 3372973..0000000
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/Feature.java
+++ /dev/null
@@ -1,81 +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.model;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class Feature {
-
-    private String name;
-    private String version;
-    private List<String> dependencies = new ArrayList<String>();
-    private List<BundleRef> bundles = new ArrayList<BundleRef>();
-	private List<ConfigRef> configs = new ArrayList<ConfigRef>();
-    private List<ArtifactRef> configFiles = new ArrayList<ArtifactRef>();
-
-    public Feature(String name) {
-        this.name = name;
-    }
-
-    public String getName() {
-        return name;
-    }
-    
-    public String getVersion() {
-        return version;
-    }
-    
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public List<String> getDependencies() {
-        return dependencies;
-    }
-
-    public List<BundleRef> getBundles() {
-        return bundles;
-    }
-
-	public List<ConfigRef> getConfigurations() {
-		return configs;
-    }
-
-    public List<ArtifactRef> getConfigFiles() {
-        return configFiles;
-    }
-
-    public void addDependency(String dependency) {
-        dependencies.add(dependency);
-    }
-
-    public void addBundle(BundleRef bundle) {
-        bundles.add(bundle);
-    }
-
-	public void addConfig(ConfigRef config) {
-		configs.add(config);
-    }
-
-    public void addConfigFile(ArtifactRef configFile) {
-        configFiles.add(configFile);
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/Repository.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/Repository.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/Repository.java
deleted file mode 100644
index 5e539cf..0000000
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/model/Repository.java
+++ /dev/null
@@ -1,152 +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.model;
-
-import java.io.ByteArrayInputStream;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-public class Repository {
-
-    private URI uri;
-    private List<Feature> features;
-    private List<String> repositories;
-    private Integer defaultStartLevel;
-
-    public Repository(URI uri, Integer defaultStartLevel) {
-        this.uri = uri;
-        this.defaultStartLevel = defaultStartLevel;
-    }
-
-    public URI getURI() {
-        return uri;
-    }
-
-    public Feature[] getFeatures() {
-        if (features == null) {
-            loadFeatures();
-        }
-        return features.toArray(new Feature[features.size()]);
-    }
-
-    public String[] getDefinedRepositories() {
-        if (repositories == null) {
-            loadRepositories();
-        }
-        return repositories.toArray(new String[repositories.size()]);
-    }
-
-    private void loadRepositories() {
-        try {
-            repositories = new ArrayList<String>();
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            Document doc = factory.newDocumentBuilder().parse(uri.toURL().openStream());
-            NodeList nodes = doc.getDocumentElement().getChildNodes();
-            for (int i = 0; i < nodes.getLength(); i++) {
-                org.w3c.dom.Node node = nodes.item(i);
-                if (!(node instanceof Element) || !"repository".equals(node.getNodeName())) {
-                    continue;
-                }
-                Element e = (Element) nodes.item(i);
-                repositories.add(e.getTextContent().trim());
-            }
-        } catch (Exception e) {
-            throw new RuntimeException("Error loading feature descriptors from " + this.uri, e);
-        }
-    }
-
-    private void loadFeatures() {
-        try {
-            features = new ArrayList<Feature>();
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            Document doc = factory.newDocumentBuilder().parse(uri.toURL().openStream());
-            NodeList nodes = doc.getDocumentElement().getChildNodes();
-            for (int i = 0; i < nodes.getLength(); i++) {
-                org.w3c.dom.Node node = nodes.item(i);
-                if (!(node instanceof Element) || !"feature".equals(node.getNodeName())) {
-                    continue;
-                }
-                Element e = (Element) nodes.item(i);
-                String name = e.getAttribute("name");
-                String version = e.getAttribute("version");
-                Feature f = new Feature(name);
-                f.setVersion(version);
-                NodeList featureNodes = e.getElementsByTagName("feature");
-                for (int j = 0; j < featureNodes.getLength(); j++) {
-                    Element b = (Element) featureNodes.item(j);
-                    if (b.getAttribute("version") != null 
-                        && b.getAttribute("version").length() > 0) {
-                        f.addDependency(b.getTextContent() + "/" + b.getAttribute("version"));
-                    } else {
-                        f.addDependency(b.getTextContent());
-                    }
-                }
-                NodeList configNodes = e.getElementsByTagName("config");
-                for (int j = 0; j < configNodes.getLength(); j++) {
-                    Element c = (Element) configNodes.item(j);
-                    String cfgName = c.getAttribute("name");
-                    String data = c.getTextContent();
-					String append = c.getAttribute("append");
-                    Properties properties = new Properties();
-                    properties.load(new ByteArrayInputStream(data.getBytes()));
-                    Map<String, String> hashtable = new Hashtable<String, String>();
-                    for (Object key : properties.keySet()) {
-                        String n = key.toString();
-                        hashtable.put(n, properties.getProperty(n));
-                    }
-					f.addConfig(new ConfigRef(cfgName, hashtable, append));
-                }
-                NodeList configFileNodes = e.getElementsByTagName("configfile");
-                for (int j = 0; j < configFileNodes.getLength(); j++) {
-                    Element c = (Element) configFileNodes.item(j);
-                    f.addConfigFile(new ArtifactRef(c.getTextContent()));
-                }
-                NodeList bundleNodes = e.getElementsByTagName("bundle");
-                for (int j = 0; j < bundleNodes.getLength(); j++) {
-                    Element b = (Element) bundleNodes.item(j);
-                    Integer startLevel = getInt(b, "start-level", defaultStartLevel);
-                    f.addBundle(new BundleRef(b.getTextContent(), startLevel));
-                }
-                features.add(f);
-            }
-        } catch (Exception e) {
-            throw new RuntimeException("Error loading features for " + this.uri, e);
-        }
-    }
-
-    private Integer getInt(Element el, String key, Integer defaultValue) {
-        Integer value;
-        try {
-            value = Integer.parseInt(el.getAttribute(key));
-        } catch (Exception e1) {
-            value = null;
-        }
-        return (value == null || value == 0) ? defaultValue : value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/Dependency30Helper.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/Dependency30Helper.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/Dependency30Helper.java
new file mode 100644
index 0000000..c06e0a5
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/Dependency30Helper.java
@@ -0,0 +1,378 @@
+/*
+ * 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 org.apache.maven.RepositoryUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.sonatype.aether.RepositorySystem;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.collection.*;
+import org.sonatype.aether.graph.Dependency;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.resolution.ArtifactRequest;
+import org.sonatype.aether.resolution.ArtifactResolutionException;
+import org.sonatype.aether.resolution.ArtifactResult;
+import org.sonatype.aether.util.DefaultRepositorySystemSession;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+import org.sonatype.aether.util.graph.selector.AndDependencySelector;
+import org.sonatype.aether.util.graph.selector.ExclusionDependencySelector;
+import org.sonatype.aether.util.graph.selector.OptionalDependencySelector;
+import org.sonatype.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
+import org.sonatype.aether.util.graph.transformer.ConflictMarker;
+import org.sonatype.aether.util.graph.transformer.JavaDependencyContextRefiner;
+import org.sonatype.aether.util.graph.transformer.JavaEffectiveScopeCalculator;
+
+import java.io.File;
+import java.util.*;
+
+import static java.lang.String.*;
+import static org.apache.karaf.deployer.kar.KarArtifactInstaller.FEATURE_CLASSIFIER;
+
+/**
+ * This is a dependency helper compliant with Maven 3.0 (using Aether Sonatype lib)
+ */
+public class Dependency30Helper implements DependencyHelper {
+
+    /**
+     * The entry point to Aether, i.e. the component doing all the work.
+     */
+    private final RepositorySystem repositorySystem;
+
+    /**
+     * The current repository/network configuration of Maven.
+     */
+    private final RepositorySystemSession repositorySystemSession;
+
+    /**
+     * The project's defined repositories to use for the resolution of project dependencies.
+     */
+    private final List<RemoteRepository> projectRepositories;
+
+    // dependencies we are interested in
+    protected Map<Artifact, String> localDependencies;
+    // log of what happened during search
+    protected String treeListing;
+
+    public Dependency30Helper(List<RemoteRepository> projectRepositories, RepositorySystemSession repositorySystemSession, RepositorySystem repositorySystem) {
+        this.projectRepositories = projectRepositories;
+        this.repositorySystemSession = repositorySystemSession;
+        this.repositorySystem = repositorySystem;
+    }
+
+    @Override
+    public Map<Artifact, String> getLocalDependencies() {
+        return this.localDependencies;
+    }
+
+    @Override
+    public String getTreeListing() {
+        return this.treeListing;
+    }
+
+    @Override
+    public void getDependencies(MavenProject project, boolean useTransitiveDependencies) throws MojoExecutionException {
+        DependencyNode rootNode = getDependencyTree(RepositoryUtils.toArtifact(project.getArtifact()));
+        Scanner scanner = new Scanner();
+        scanner.scan(rootNode, useTransitiveDependencies);
+        localDependencies = scanner.localDependencies;
+        treeListing = scanner.getLog();
+    }
+
+    private DependencyNode getDependencyTree(Artifact artifact) throws MojoExecutionException {
+        try {
+            CollectRequest collectRequest = new CollectRequest(new Dependency(artifact, "compile"), null, projectRepositories);
+            DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(repositorySystemSession);
+            session.setDependencySelector(new AndDependencySelector(new OptionalDependencySelector(),
+                    new ScopeDependencySelector1(),
+                    new ExclusionDependencySelector()));
+            DependencyGraphTransformer transformer = new ChainedDependencyGraphTransformer(new ConflictMarker(),
+                    new JavaEffectiveScopeCalculator(),
+                    new JavaDependencyContextRefiner());
+            session.setDependencyGraphTransformer(transformer);
+            CollectResult result = repositorySystem.collectDependencies(session, collectRequest);
+            return result.getRoot();
+        } catch (DependencyCollectionException e) {
+            throw new MojoExecutionException("Cannot build project dependency tree", e);
+        }
+    }
+
+    /**
+     * Aether's ScopeDependencySelector appears to always exclude the configured scopes (test and provided) and there is no way to configure it to
+     * accept the top level provided scope dependencies. We need this 3 layers cake since Aether never actually uses the top level selector you give it,
+     * it always starts by getting the child to apply to the project's dependencies.
+     */
+    private static class ScopeDependencySelector1 implements DependencySelector {
+
+        private DependencySelector child = new ScopeDependencySelector2();
+
+        public boolean selectDependency(Dependency dependency) {
+            throw new IllegalStateException("This does not appear to be called");
+        }
+
+        public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
+            return child;
+        }
+
+    }
+
+    private static class ScopeDependencySelector2 implements DependencySelector {
+
+        private DependencySelector child = new ScopeDependencySelector3();
+
+        public boolean selectDependency(Dependency dependency) {
+            String scope = dependency.getScope();
+            return !"test".equals(scope) && !"runtime".equals(scope);
+        }
+
+        public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
+            return child;
+        }
+
+    }
+
+    private static class ScopeDependencySelector3 implements DependencySelector {
+
+        public boolean selectDependency(Dependency dependency) {
+            String scope = dependency.getScope();
+            return !"test".equals(scope) && !"provided".equals(scope) && !"runtime".equals(scope);
+        }
+
+        public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
+            return this;
+        }
+
+    }
+
+    private static class Scanner {
+
+        private static enum Accept {
+            ACCEPT(true, true),
+            PROVIDED(true, false),
+            STOP(false, false);
+
+            private final boolean more;
+            private final boolean local;
+
+            private Accept(boolean more, boolean local) {
+                this.more = more;
+                this.local = local;
+            }
+
+            public boolean isContinue() {
+                return more;
+            }
+
+            public boolean isLocal() {
+                return local;
+            }
+
+        }
+
+        // all the dependencies needed, with provided dependencies removed
+        private final Map<Artifact, String> localDependencies = new LinkedHashMap<Artifact, String>();
+        // dependencies from ancestor, to be removed from localDependencies
+        private final Set<Artifact> dependencies = new LinkedHashSet<Artifact>();
+
+        private final StringBuilder log = new StringBuilder();
+
+        public void scan(DependencyNode rootNode, boolean useTransitiveDependencies) throws MojoExecutionException {
+            for (DependencyNode child : rootNode.getChildren()) {
+                scan(child, Accept.ACCEPT, useTransitiveDependencies, false, "");
+            }
+            if (useTransitiveDependencies) {
+                localDependencies.keySet().removeAll(dependencies);
+            }
+        }
+
+        private void scan(DependencyNode dependencyNode, Accept parentAccept, boolean useTransitiveDependencies, boolean isFromFeature, String indent) throws MojoExecutionException {
+            Accept accept = accept(dependencyNode, parentAccept);
+            if (accept.isLocal()) {
+                if (isFromFeature) {
+                    if (!isFeature(dependencyNode)) {
+                        log.append(indent).append("from feature: ").append(dependencyNode).append("\n");
+                        dependencies.add(dependencyNode.getDependency().getArtifact());
+                    } else {
+                        log.append(indent).append("is feature: ").append(dependencyNode).append("\n");
+                    }
+                } else {
+                    log.append(indent).append("local: ").append(dependencyNode).append("\n");
+                    if (localDependencies.containsKey(dependencyNode.getDependency().getArtifact())) {
+                        log.append(indent).append("already in feature, returning:").append(dependencyNode).append("\n");
+                        return;
+                    }
+                    // TODO resolve scope conflicts
+                    localDependencies.put(dependencyNode.getDependency().getArtifact(), dependencyNode.getDependency().getScope());
+                    if (isFeature(dependencyNode) || !useTransitiveDependencies) {
+                        isFromFeature = true;
+                    }
+                }
+                if (useTransitiveDependencies && accept.isContinue()) {
+                    List<DependencyNode> children = dependencyNode.getChildren();
+                    for (DependencyNode child : children) {
+                        scan(child, accept, useTransitiveDependencies, isFromFeature, indent + " ");
+                    }
+                }
+            }
+        }
+
+        public String getLog() {
+            return log.toString();
+        }
+
+        private Accept accept(DependencyNode dependency, Accept previous) {
+            String scope = dependency.getDependency().getScope();
+            if (scope == null || "runtime".equalsIgnoreCase(scope) || "compile".equalsIgnoreCase(scope)) {
+                return previous;
+            }
+            if ("provided".equalsIgnoreCase(scope)) {
+                return Accept.PROVIDED;
+            }
+            return Accept.STOP;
+        }
+
+    }
+
+    public static boolean isFeature(DependencyNode dependencyNode) {
+        return isFeature(dependencyNode.getDependency().getArtifact());
+    }
+
+    public static boolean isFeature(Artifact artifact) {
+        return artifact.getExtension().equals("kar") || FEATURE_CLASSIFIER.equals(artifact.getClassifier());
+    }
+
+    @Override
+    public boolean isArtifactAFeature(Object artifact) {
+        return Dependency30Helper.isFeature((Artifact) artifact);
+    }
+
+    @Override
+    public String getArtifactId(Object artifact) {
+        return ((Artifact) artifact).getArtifactId();
+    }
+
+    @Override
+    public String getClassifier(Object artifact) {
+        return ((Artifact) artifact).getClassifier();
+    }
+
+    @Override
+    public File resolve(Object artifact, Log log) {
+        ArtifactRequest request = new ArtifactRequest();
+        request.setArtifact((Artifact) artifact);
+        request.setRepositories(projectRepositories);
+
+        log.debug("Resolving artifact " + artifact + " from " + projectRepositories);
+
+        ArtifactResult result;
+        try {
+            result = repositorySystem.resolveArtifact(repositorySystemSession, request);
+        } catch (ArtifactResolutionException e) {
+            log.warn("Could not resolve " + artifact, e);
+            return null;
+        }
+
+        log.debug("Resolved artifact " + artifact + " to " + result.getArtifact().getFile() + " from " + result.getRepository());
+
+        return result.getArtifact().getFile();
+    }
+
+    @Override
+    public File resolveById(String id, Log log) throws MojoFailureException {
+        if (id.startsWith("mvn:")) {
+            if (id.contains("!")) {
+                id = id.substring(0, "mvn:".length()) + id.substring(id.indexOf("!") + 1);
+            }
+            if (id.endsWith("/")) {
+                id = id.substring(0, id.length() - 1);
+            }
+        }
+        id = MavenUtil.mvnToAether(id);
+        ArtifactRequest request = new ArtifactRequest();
+        request.setArtifact(new DefaultArtifact(id));
+        request.setRepositories((List<RemoteRepository>) projectRepositories);
+
+        log.debug("Resolving artifact " + id + " from " + projectRepositories);
+
+        ArtifactResult result;
+        try {
+            result = repositorySystem.resolveArtifact(repositorySystemSession, request);
+        } catch (ArtifactResolutionException e) {
+            log.warn("Could not resolve " + id, e);
+            throw new MojoFailureException(format("Couldn't resolve artifact %s", id), e);
+        }
+
+        log.debug("Resolved artifact " + id + " to " + result.getArtifact().getFile() + " from " + result.getRepository());
+
+        return result.getArtifact().getFile();
+    }
+
+    @Override
+    public String artifactToMvn(org.apache.maven.artifact.Artifact artifact) {
+        return this.artifactToMvn(RepositoryUtils.toArtifact(artifact));
+    }
+
+    @Override
+    public String artifactToMvn(Object _artifact) {
+        Artifact artifact = (Artifact) _artifact;
+        String bundleName;
+        if (artifact.getExtension().equals("jar") && MavenUtil.isEmpty(artifact.getClassifier())) {
+            bundleName = String.format("mvn:%s/%s/%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion());
+        } else {
+            if (MavenUtil.isEmpty(artifact.getClassifier())) {
+                bundleName = String.format("mvn:%s/%s/%s/%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), artifact.getExtension());
+            } else {
+                bundleName = String.format("mvn:%s/%s/%s/%s/%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), artifact.getExtension(), artifact.getClassifier());
+            }
+        }
+        return bundleName;
+    }
+
+    @Override
+    public org.apache.maven.artifact.Artifact mvnToArtifact(String name) {
+        name = MavenUtil.mvnToAether(name);
+        DefaultArtifact artifact = new DefaultArtifact(name);
+        org.apache.maven.artifact.Artifact mavenArtifact = RepositoryUtils.toArtifact(artifact);
+        return mavenArtifact;
+    }
+
+    @Override
+    public String pathFromMaven(String name) {
+        if (name.indexOf(':') == -1) {
+            return name;
+        }
+        if (name.endsWith("/")) {
+            name = name.substring(0, name.length() - 1);
+        }
+        name = MavenUtil.mvnToAether(name);
+        return pathFromAether(name);
+    }
+
+    @Override
+    public String pathFromAether(String name) {
+        DefaultArtifact artifact = new DefaultArtifact(name);
+        org.apache.maven.artifact.Artifact mavenArtifact = RepositoryUtils.toArtifact(artifact);
+        return MavenUtil.layout.pathOf(mavenArtifact);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/Dependency31Helper.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/Dependency31Helper.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/Dependency31Helper.java
new file mode 100644
index 0000000..215619e
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/Dependency31Helper.java
@@ -0,0 +1,403 @@
+/*
+ * 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 org.apache.maven.RepositoryUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.collection.*;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.util.graph.selector.AndDependencySelector;
+import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector;
+import org.eclipse.aether.util.graph.selector.OptionalDependencySelector;
+import org.eclipse.aether.util.graph.transformer.*;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import static java.lang.String.*;
+import static org.apache.karaf.deployer.kar.KarArtifactInstaller.FEATURE_CLASSIFIER;
+
+/**
+ * <p>{@link DependencyHelper} for accessing Eclipse Aether system used in Maven 3.1+. It uses reflection to access
+ * these methods of {@code maven-core} APIs which directly references Eclipse Aether classes.</p>
+ *
+ * <p>When {@code karaf-maven-plugin} switches to {@code maven-core:3.1.0+}, reflection should be use for Sonatype
+ * Aether in {@link Dependency30Helper} and this class will use Maven API directly.</p>
+ */
+public class Dependency31Helper implements DependencyHelper {
+
+    /**
+     * The entry point to Aether, i.e. the component doing all the work.
+     */
+    private final RepositorySystem repositorySystem;
+
+    /**
+     * The current repository/network configuration of Maven.
+     */
+    private final RepositorySystemSession repositorySystemSession;
+
+    /**
+     * The project's remote repositories to use for the resolution of project dependencies.
+     */
+    private final List<RemoteRepository> projectRepositories;
+
+    // dependencies we are interested in
+    protected Map<Artifact, String> localDependencies;
+    // log of what happened during search
+    protected String treeListing;
+
+    @SuppressWarnings("unchecked")
+    public Dependency31Helper(List<?> repositories, Object session, RepositorySystem repositorySystem) {
+        this.projectRepositories = (List<RemoteRepository>) repositories;
+        this.repositorySystemSession = (RepositorySystemSession) session;
+        this.repositorySystem = repositorySystem;
+    }
+
+    @Override
+    public Map<?, String> getLocalDependencies() {
+        return localDependencies;
+    }
+
+    @Override
+    public String getTreeListing() {
+        return treeListing;
+    }
+
+    @Override
+    public void getDependencies(MavenProject project, boolean useTransitiveDependencies) throws MojoExecutionException {
+        DependencyNode rootNode = getDependencyTree(toArtifact(project.getArtifact()));
+
+        Scanner scanner = new Scanner();
+        scanner.scan(rootNode, useTransitiveDependencies);
+        localDependencies = scanner.localDependencies;
+        treeListing = scanner.getLog();
+    }
+
+    private DependencyNode getDependencyTree(Artifact artifact) throws MojoExecutionException {
+        try {
+            CollectRequest collectRequest = new CollectRequest(new Dependency(artifact, "compile"), null, projectRepositories);
+            DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(repositorySystemSession);
+            session.setDependencySelector(new AndDependencySelector(new OptionalDependencySelector(),
+                    new ScopeDependencySelector1(),
+                    new ExclusionDependencySelector()));
+            // between aether-util 0.9.0.M1 and M2, JavaEffectiveScopeCalculator was removed
+            // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=397241
+            DependencyGraphTransformer transformer = new ChainedDependencyGraphTransformer(new ConflictMarker(),
+                    new ConflictResolver(new NearestVersionSelector(), new JavaScopeSelector(), new SimpleOptionalitySelector(), new JavaScopeDeriver()),
+                    new JavaDependencyContextRefiner());
+            session.setDependencyGraphTransformer(transformer);
+            CollectResult result = repositorySystem.collectDependencies(session, collectRequest);
+            return result.getRoot();
+        } catch (DependencyCollectionException e) {
+            throw new MojoExecutionException("Cannot build project dependency tree", e);
+        }
+    }
+
+    /**
+     * Aether's ScopeDependencySelector appears to always exclude the configured scopes (test and provided) and there is no way to configure it to
+     * accept the top level provided scope dependencies. We need this 3 layers cake since Aether never actually uses the top level selector you give it,
+     * it always starts by getting the child to apply to the project's dependencies.
+     */
+    private static class ScopeDependencySelector1 implements DependencySelector {
+
+        private DependencySelector child = new ScopeDependencySelector2();
+
+        public boolean selectDependency(Dependency dependency) {
+            throw new IllegalStateException("This does not appear to be called");
+        }
+
+        public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
+            return child;
+        }
+
+    }
+
+    public static class ScopeDependencySelector2 implements DependencySelector {
+
+        private DependencySelector child = new ScopeDependencySelector3();
+
+        public boolean selectDependency(Dependency dependency) {
+            String scope = dependency.getScope();
+            return !"test".equals(scope) && !"runtime".equals(scope);
+        }
+
+        public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
+            return child;
+        }
+
+    }
+
+    private static class ScopeDependencySelector3 implements DependencySelector {
+
+        public boolean selectDependency(Dependency dependency) {
+            String scope = dependency.getScope();
+            return !"test".equals(scope) && !"provided".equals(scope) && !"runtime".equals(scope);
+        }
+
+        public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
+            return this;
+        }
+
+    }
+
+    private static class Scanner {
+
+        private static enum Accept {
+            ACCEPT(true, true),
+            PROVIDED(true, false),
+            STOP(false, false);
+
+            private final boolean more;
+            private final boolean local;
+
+            private Accept(boolean more, boolean local) {
+                this.more = more;
+                this.local = local;
+            }
+
+            public boolean isContinue() {
+                return more;
+            }
+
+            public boolean isLocal() {
+                return local;
+            }
+        }
+
+        // all the dependencies needed, with provided dependencies removed
+        private final Map<Artifact, String> localDependencies = new LinkedHashMap<Artifact, String>();
+
+        // dependencies from ancestor, to be removed from localDependencies
+        private final Set<Artifact> dependencies = new LinkedHashSet<Artifact>();
+
+        private final StringBuilder log = new StringBuilder();
+
+        public void scan(DependencyNode rootNode, boolean useTransitiveDependencies) throws MojoExecutionException {
+            for (DependencyNode child : rootNode.getChildren()) {
+                scan(child, Accept.ACCEPT, useTransitiveDependencies, false, "");
+            }
+            if (useTransitiveDependencies) {
+                localDependencies.keySet().removeAll(dependencies);
+            }
+        }
+
+        private void scan(DependencyNode dependencyNode, Accept parentAccept, boolean useTransitiveDependencies, boolean isFromFeature, String indent) throws MojoExecutionException {
+            Accept accept = accept(dependencyNode, parentAccept);
+            if (accept.isLocal()) {
+                if (isFromFeature) {
+                    if (!isFeature(dependencyNode)) {
+                        log.append(indent).append("from feature:").append(dependencyNode).append("\n");
+                        dependencies.add(dependencyNode.getDependency().getArtifact());
+                    } else {
+                        log.append(indent).append("is feature:").append(dependencyNode).append("\n");
+                    }
+                } else {
+                    log.append(indent).append("local:").append(dependencyNode).append("\n");
+                    if (localDependencies.containsKey(dependencyNode.getDependency().getArtifact())) {
+                        log.append(indent).append("already in feature, returning:").append(dependencyNode).append("\n");
+                        return;
+                    }
+                    // TODO resolve scope conflicts
+                    localDependencies.put(dependencyNode.getDependency().getArtifact(), dependencyNode.getDependency().getScope());
+                    if (isFeature(dependencyNode) || !useTransitiveDependencies) {
+                        isFromFeature = true;
+                    }
+                }
+                if (useTransitiveDependencies && accept.isContinue()) {
+                    List<DependencyNode> children = dependencyNode.getChildren();
+                    for (DependencyNode child : children) {
+                        scan(child, accept, useTransitiveDependencies, isFromFeature, indent + " ");
+                    }
+                }
+            }
+        }
+
+        public String getLog() {
+            return log.toString();
+        }
+
+        private Accept accept(DependencyNode dependency, Accept previous) {
+            String scope = dependency.getDependency().getScope();
+            if (scope == null || "runtime".equalsIgnoreCase(scope) || "compile".equalsIgnoreCase(scope)) {
+                return previous;
+            }
+            if ("provided".equalsIgnoreCase(scope)) {
+                return Accept.PROVIDED;
+            }
+            return Accept.STOP;
+        }
+
+
+    }
+
+    public static boolean isFeature(DependencyNode dependencyNode) {
+        return isFeature(dependencyNode.getDependency().getArtifact());
+    }
+
+    public static boolean isFeature(Artifact artifact) {
+        return artifact.getExtension().equals("kar") || FEATURE_CLASSIFIER.equals(artifact.getClassifier());
+    }
+
+    @Override
+    public boolean isArtifactAFeature(Object artifact) {
+        return Dependency31Helper.isFeature((Artifact) artifact);
+    }
+
+    @Override
+    public String getArtifactId(Object artifact) {
+        return ((Artifact) artifact).getArtifactId();
+    }
+
+    @Override
+    public String getClassifier(Object artifact) {
+        return ((Artifact) artifact).getClassifier();
+    }
+
+    @Override
+    public File resolve(Object artifact, Log log) {
+        ArtifactRequest request = new ArtifactRequest();
+        request.setArtifact((Artifact) artifact);
+        request.setRepositories(projectRepositories);
+
+        log.debug("Resolving artifact " + artifact + " from " + projectRepositories);
+
+        ArtifactResult result;
+        try {
+            result = repositorySystem.resolveArtifact(repositorySystemSession, request);
+        } catch (ArtifactResolutionException e) {
+            log.warn("Cound not resolve " + artifact, e);
+            return null;
+        }
+
+        log.debug("Resolved artifact " + artifact + " to " + result.getArtifact().getFile() + " from " + result.getRepository());
+
+        return result.getArtifact().getFile();
+    }
+
+    @Override
+    public File resolveById(String id, Log log) throws MojoFailureException {
+        if (id.startsWith("mvn:")) {
+            if (id.contains("!")) {
+                id = id.substring(0, "mvn:".length()) + id.substring(id.indexOf("!") + 1);
+            }
+            if (id.endsWith("/")) {
+                id = id.substring(0, id.length() - 1);
+            }
+        }
+        id = MavenUtil.mvnToAether(id);
+        ArtifactRequest request = new ArtifactRequest();
+        request.setArtifact(new DefaultArtifact(id));
+        request.setRepositories(projectRepositories);
+
+        log.debug("Resolving artifact " + id + " from " + projectRepositories);
+
+        ArtifactResult result;
+        try {
+            result = repositorySystem.resolveArtifact(repositorySystemSession, request);
+        } catch (ArtifactResolutionException e) {
+            log.warn("Could not resolve " + id, e);
+            throw new MojoFailureException(format("Couldn't resolve artifact %s", id), e);
+        }
+
+        log.debug("Resolved artifact " + id + " to " + result.getArtifact().getFile() + " from " + result.getRepository());
+
+        return result.getArtifact().getFile();
+    }
+
+    @Override
+    public String artifactToMvn(org.apache.maven.artifact.Artifact artifact) throws MojoExecutionException {
+        return this.artifactToMvn(toArtifact(artifact));
+    }
+
+    @Override
+    public String artifactToMvn(Object _artifact) {
+        Artifact artifact = (Artifact) _artifact;
+        String bundleName;
+        if (artifact.getExtension().equals("jar") && MavenUtil.isEmpty(artifact.getClassifier())) {
+            bundleName = String.format("mvn:%s/%s/%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion());
+        } else {
+            if (MavenUtil.isEmpty(artifact.getClassifier())) {
+                bundleName = String.format("mvn:%s/%s/%s/%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), artifact.getExtension());
+            } else {
+                bundleName = String.format("mvn:%s/%s/%s/%s/%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), artifact.getExtension(), artifact.getClassifier());
+            }
+        }
+        return bundleName;
+    }
+
+    private static Artifact toArtifact(org.apache.maven.artifact.Artifact artifact) throws MojoExecutionException {
+        try {
+            Method toArtifact = RepositoryUtils.class.getMethod("toArtifact", org.apache.maven.artifact.Artifact.class);
+            return (Artifact) toArtifact.invoke(null, artifact);
+        } catch (Exception e) {
+            throw new MojoExecutionException(e.getMessage(), e);
+        }
+    }
+
+    private static org.apache.maven.artifact.Artifact toArtifact(Artifact artifact) throws MojoExecutionException {
+        try {
+            Method toArtifact = RepositoryUtils.class.getMethod("toArtifact", Artifact.class);
+            return (org.apache.maven.artifact.Artifact) toArtifact.invoke(null, artifact);
+        } catch (Exception e) {
+            throw new MojoExecutionException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public org.apache.maven.artifact.Artifact mvnToArtifact(String name) throws MojoExecutionException {
+        name = MavenUtil.mvnToAether(name);
+        DefaultArtifact artifact = new DefaultArtifact(name);
+        org.apache.maven.artifact.Artifact mavenArtifact = toArtifact(artifact);
+        return mavenArtifact;
+    }
+
+    @Override
+    public String pathFromMaven(String name) throws MojoExecutionException {
+        if (name.indexOf(':') == -1) {
+            return name;
+        }
+        if (name.endsWith("/")) {
+            name = name.substring(0, name.length() - 1);
+        }
+        name = MavenUtil.mvnToAether(name);
+        return pathFromAether(name);
+    }
+
+    @Override
+    public String pathFromAether(String name) throws MojoExecutionException {
+        DefaultArtifact artifact = new DefaultArtifact(name);
+        org.apache.maven.artifact.Artifact mavenArtifact = toArtifact(artifact);
+        return MavenUtil.layout.pathOf(mavenArtifact);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/DependencyHelper.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/DependencyHelper.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/DependencyHelper.java
new file mode 100644
index 0000000..ece73c4
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/DependencyHelper.java
@@ -0,0 +1,88 @@
+/*
+ * 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.util.Map;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * <p>An interface for accessing available Aether subsystem (Sonatype for Maven 3.0.x or Eclipse for Maven 3.1.x)</p>
+ *
+ * <p>Some methods have {@link Object} parameters because they should be able to receive Aether classes from
+ * both Aether variants.</p>
+ */
+public interface DependencyHelper {
+
+    public abstract Map<?, String> getLocalDependencies();
+
+    public abstract String getTreeListing();
+
+    public abstract void getDependencies(MavenProject project, boolean useTransitiveDependencies) throws MojoExecutionException;
+
+    public boolean isArtifactAFeature(Object artifact);
+
+    public abstract String getArtifactId(Object artifact);
+
+    public abstract String getClassifier(Object artifact);
+
+    public abstract File resolve(Object artifact, Log log);
+
+    public abstract File resolveById(String id, Log log) throws MojoFailureException;
+
+    /**
+     * Convert a Maven <code>Artifact</code> into a PAX URL mvn format.
+     *
+     * @param artifact the Maven <code>Artifact</code>.
+     * @return the corresponding PAX URL mvn format (mvn:groupId/artifactId/version/type/classifier)
+     */
+    public String artifactToMvn(Artifact artifact) throws MojoExecutionException;
+
+    /**
+     * Convert an Aether (Sonatype or Eclipse) artifact into a PAX URL mvn format.
+     *
+     * @param object the Aether <code>org.sonatype|eclipse.aether.artifact.Artifact</code>.
+     * @return the corresponding PAX URL mvn format (mvn:groupId/artifactId/version/type/classifier)
+     */
+    public String artifactToMvn(Object object) throws MojoExecutionException;
+
+    public Artifact mvnToArtifact(String name) throws MojoExecutionException;
+
+    /**
+     * Convert a PAX URL mvn format into a filesystem path.
+     *
+     * @param name PAX URL mvn format (mvn:groupId/artifactId/version/type/classifier).
+     * @return a filesystem path.
+     */
+    public String pathFromMaven(String name) throws MojoExecutionException;
+
+    /**
+     * Convert an Aether coordinate format into a filesystem path.
+     *
+     * @param name the Aether coordinate format (groupId:artifactId[:extension[:classifier]]:version).
+     * @return the filesystem path.
+     */
+    public String pathFromAether(String name) throws MojoExecutionException;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/DependencyHelperFactory.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/DependencyHelperFactory.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/DependencyHelperFactory.java
new file mode 100644
index 0000000..f278e7b
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/DependencyHelperFactory.java
@@ -0,0 +1,76 @@
+/*
+ * 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 org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.sonatype.aether.repository.RemoteRepository;
+
+import java.util.List;
+
+/**
+ * <p>Service-locator based factory for available Aether system (Sonatype for Maven 3.0.x or Eclipse for Maven 3.1.x)</p>
+ */
+public class DependencyHelperFactory {
+
+    /**
+     * <p>Create a new {@link DependencyHelper} based on what has been found in {@link org.codehaus.plexus.PlexusContainer}</p>
+     *
+     * <p>{@code karaf-maven-plugin} depends on {@code maven-core:3.0}, so for Maven 3.0.x, it may use this API directly.
+     * When using Maven 3.1.x/3.2.x, it should use reflection to invoke org.apache.maven.RepositoryUtils.toArtifact(Artifact)
+     * as this method directly references specific Aether implementation.</p>
+     *
+     * <p>When {@code karaf-maven-plugin} switches to {@code maven-core:3.1.0+}, reflection should be use for Sonatype variant of Aether.</p>
+     *
+     * @param container
+     * @param mavenProject
+     * @param mavenSession
+     * @param log
+     * @return
+     * @throws MojoExecutionException
+     */
+    public static DependencyHelper createDependencyHelper(PlexusContainer container, MavenProject mavenProject, MavenSession mavenSession, Log log) throws MojoExecutionException {
+        try {
+            if (container.hasComponent("org.sonatype.aether.RepositorySystem")) {
+                org.sonatype.aether.RepositorySystem system = container.lookup(org.sonatype.aether.RepositorySystem.class);
+                org.sonatype.aether.RepositorySystemSession session = mavenSession.getRepositorySession();
+                List<RemoteRepository> repositories = mavenProject.getRemoteProjectRepositories();
+                return new Dependency30Helper(repositories, session, system);
+            } else if (container.hasComponent("org.eclipse.aether.RepositorySystem")) {
+                org.eclipse.aether.RepositorySystem system = container.lookup(org.eclipse.aether.RepositorySystem.class);
+                Object session;
+                try {
+                    session = MavenSession.class.getMethod("getRepositorySession").invoke(mavenSession);
+                } catch (Exception e) {
+                    throw new MojoExecutionException(e.getMessage(), e);
+                }
+                List<?> repositories = mavenProject.getRemoteProjectRepositories();
+                return new Dependency31Helper(repositories, session, system);
+            }
+        } catch (ComponentLookupException e) {
+            throw new MojoExecutionException(e.getMessage(), e);
+        }
+        throw new MojoExecutionException("Cannot locate either org.sonatype.aether.RepositorySystem or org.eclipse.aether.RepositorySystem");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/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
index 8d4b3f4..d9e632f 100644
--- 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
@@ -20,7 +20,6 @@ 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;

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/ManifestUtils.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/ManifestUtils.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/ManifestUtils.java
new file mode 100644
index 0000000..3e93624
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/ManifestUtils.java
@@ -0,0 +1,141 @@
+/**
+ *
+ * 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.util.LinkedList;
+import java.util.List;
+import java.util.jar.Manifest;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.apache.felix.utils.version.VersionRange;
+import org.osgi.framework.Constants;
+
+
+/**
+ * A set of utility methods to ease working with {@link org.apache.felix.utils.manifest.Parser} and
+ * {@link org.apache.felix.utils.manifest.Clause}
+ */
+
+public class ManifestUtils {
+
+    private ManifestUtils() {
+        // hide the constructor
+    }
+
+    /**
+     * Get the list of imports from the manifest.  If no imports have been defined, this method returns an empty list.
+     *
+     * @param manifest the manifest
+     * @return the list of imports
+     */
+    public static List<Clause> getImports(Manifest manifest) {
+    	List<Clause> result = new LinkedList<Clause>();
+    	Clause[] clauses = Parser.parseHeader(getHeader(Constants.IMPORT_PACKAGE, manifest));
+    	for (Clause clause : clauses) {
+    		result.add(clause);
+    	}
+    	return result;
+    }
+
+    /**
+     * Get the list of non-optional imports from the manifest.
+     *
+     * @param manifest the manifest
+     * @return the list of non-optional imports
+     */
+    public static List<Clause> getMandatoryImports(Manifest manifest) {
+        List<Clause> result = new LinkedList<Clause>();
+        for (Clause clause : getImports(manifest)) {
+            if (!isOptional(clause)) {
+                result.add(clause);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Get the list of exports from the manifest.  If no exports have been defined, this method returns an empty list.
+     *
+     * @param manifest the manifest
+     * @return the list of exports
+     */
+    public static List<Clause> getExports(Manifest manifest) {
+    	List<Clause> result = new LinkedList<Clause>();
+    	Clause[] clauses = Parser.parseHeader(getHeader(Constants.EXPORT_PACKAGE, manifest));
+    	for (Clause clause : clauses) {
+    		result.add(clause);
+    	}
+    	return result;
+    }
+
+    /**
+     * Check if a given manifest clause represents an optional import
+     *
+     * @param clause the manifest clause
+     * @return <code>true</code> for an optional import, <code>false</code> for mandatory imports
+     */
+    public static boolean isOptional(Clause clause) {
+        return "optional".equals(clause.getDirective("resolution"));
+    }
+
+    /**
+     * Check if the manifest contains the mandatory Bundle-Symbolic-Name
+     *
+     * @param manifest the manifest
+     * @return <code>true</code> if the manifest specifies a Bundle-Symbolic-Name
+     */
+    public static boolean isBundle(Manifest manifest) {
+        return getBsn(manifest) != null;
+    }
+
+    public static boolean matches(Clause requirement, Clause export) {
+        if (requirement.getName().equals(export.getName())) {
+        	VersionRange importVersionRange = getVersionRange(requirement); 
+        	VersionRange exportVersionRange = getVersionRange(export);
+        	VersionRange intersection = importVersionRange.intersect(exportVersionRange);
+        	return intersection != null;
+        }
+        return false;
+    }
+    
+    public static String getHeader(String name, Manifest manifest) {
+    	String value = manifest.getMainAttributes().getValue(name);
+    	return value;    	
+    }
+    
+    public static String getBsn(Manifest manifest) {
+    	String bsn = getHeader(Constants.BUNDLE_SYMBOLICNAME, manifest);
+        return bsn;
+    }
+    
+    @SuppressWarnings("deprecation")
+	public static VersionRange getVersionRange(Clause clause)
+    {
+        String v = clause.getAttribute(Constants.VERSION_ATTRIBUTE);
+        if (v == null)
+        {
+            v = clause.getAttribute(Constants.PACKAGE_SPECIFICATION_VERSION);
+        }
+        if (v == null)
+        {
+            v = clause.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE);
+        }
+        return VersionRange.parseVersionRange(v);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/MavenUtil.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/MavenUtil.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/MavenUtil.java
new file mode 100644
index 0000000..f1eb4ec
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/MavenUtil.java
@@ -0,0 +1,165 @@
+/*
+ * 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.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.maven.artifact.Artifact;
+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;
+
+/**
+ * Util method for Maven manipulation (URL convert, metadata generation, etc).
+ */
+public class MavenUtil {
+
+    static final DefaultRepositoryLayout layout = new DefaultRepositoryLayout();
+    private static final Pattern aetherPattern = Pattern.compile("([^: ]+):([^: ]+)(:([^: ]*)(:([^: ]+))?)?:([^: ]+)");
+    private static final Pattern mvnPattern = Pattern.compile("(?:(?:wrap:)|(?:blueprint:))?mvn:([^/ ]+)/([^/ ]+)/([^/\\$ ]*)(/([^/\\$ ]+)(/([^/\\$ ]+))?)?(/\\$.+)?");
+
+    /**
+     * Convert PAX URL mvn format to aether coordinate format.
+     * N.B. we do not handle repository-url in mvn urls.
+     * N.B. version is required in mvn urls.
+     *
+     * @param name PAX URL mvn format: mvn-uri := [ 'wrap:' ] 'mvn:' [ repository-url '!' ] group-id '/' artifact-id [ '/' [version] [ '/' [type] [ '/' classifier ] ] ] ]
+     * @return aether coordinate format: <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
+     */
+    public static String mvnToAether(String name) {
+        Matcher m = mvnPattern.matcher(name);
+        if (!m.matches()) {
+            return name;
+        }
+        StringBuilder b = new StringBuilder();
+        b.append(m.group(1)).append(":");//groupId
+        b.append(m.group(2)).append(":");//artifactId
+        String extension = m.group(5);
+        String classifier = m.group(7);
+        if (present(classifier)) {
+            if (present(extension)) {
+                b.append(extension).append(":");
+            } else {
+                b.append("jar:");
+            }
+            b.append(classifier).append(":");
+        } else {
+            if (present(extension) && !"jar".equals(extension)) {
+                b.append(extension).append(":");
+            }
+        }
+        b.append(m.group(3));
+        return b.toString();
+    }
+
+    private static boolean present(String part) {
+        return part != null && !part.isEmpty();
+    }
+
+    /**
+     * Convert Aether coordinate format to PAX mvn format.
+     * N.B. we do not handle repository-url in mvn urls.
+     * N.B. version is required in mvn urls.
+     *
+     * @param name aether coordinate format: <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
+     * @return PAX URL mvn format: mvn-uri := 'mvn:' [ repository-url '!' ] group-id '/' artifact-id [ '/' [version] [ '/' [type] [ '/' classifier ] ] ] ]
+     */
+    public static String aetherToMvn(String name) {
+        Matcher m = aetherPattern.matcher(name);
+        if (!m.matches()) {
+            return name;
+        }
+        StringBuilder b = new StringBuilder("mvn:");
+        b.append(m.group(1)).append("/");//groupId
+        b.append(m.group(2)).append("/");//artifactId
+        b.append(m.group(7));//version
+        String extension = m.group(4);
+        String classifier = m.group(6);
+        if (present(classifier)) {
+            if (present(extension)) {
+                b.append("/").append(extension);
+            } else {
+                b.append("/jar");
+            }
+            b.append("/").append(classifier);
+        } else if (present(extension)) {
+            b.append("/").append(extension);
+        }
+
+        return b.toString();
+    }
+
+    public static boolean isEmpty(String classifier) {
+        return classifier == null || classifier.length() == 0;
+    }
+
+    /**
+     * Generate the maven-metadata-local.xml for the given Maven <code>Artifact</code>.
+     *
+     * @param artifact the Maven <code>Artifact</code>.
+     * @param target   the target maven-metadata-local.xml file to generate.
+     * @throws IOException if the maven-metadata-local.xml can't be generated.
+     */
+    public static void generateMavenMetadata(Artifact artifact, File target) throws IOException {
+        target.getParentFile().mkdirs();
+        Metadata metadata = new Metadata();
+        metadata.setGroupId(artifact.getGroupId());
+        metadata.setArtifactId(artifact.getArtifactId());
+        metadata.setVersion(artifact.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(artifact.getClassifier());
+        snapshotVersion.setVersion(artifact.getVersion());
+        snapshotVersion.setExtension(artifact.getType());
+        snapshotVersion.setUpdated(versioning.getLastUpdated());
+        versioning.addSnapshotVersion(snapshotVersion);
+
+        metadata.setVersioning(versioning);
+
+        MetadataXpp3Writer metadataWriter = new MetadataXpp3Writer();
+        Writer writer = new FileWriter(target);
+        metadataWriter.write(writer, metadata);
+    }
+    
+    public static String getFileName(Artifact artifact) {
+        String name = artifact.getArtifactId() + "-" + artifact.getBaseVersion()
+            + (artifact.getClassifier() != null ? "-" + artifact.getClassifier() : "") + "." + artifact.getType();
+        return name;
+    }
+    
+    public static String getDir(Artifact artifact) {
+        return artifact.getGroupId().replace('.', '/') + "/" + artifact.getArtifactId() + "/" + artifact.getBaseVersion() + "/";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/AddToRepositoryMojoTest.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/AddToRepositoryMojoTest.java b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/AddToRepositoryMojoTest.java
deleted file mode 100644
index 5744805..0000000
--- a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/AddToRepositoryMojoTest.java
+++ /dev/null
@@ -1,60 +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 org.apache.karaf.tooling.features.model.Repository;
-import org.apache.maven.artifact.factory.DefaultArtifactFactory;
-import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
-import org.apache.maven.artifact.handler.manager.DefaultArtifactHandlerManager;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.junit.Test;
-
-import java.lang.reflect.Field;
-import java.net.URL;
-import java.util.HashMap;
-
-public class AddToRepositoryMojoTest extends AddToRepositoryMojo {
-    @SuppressWarnings("rawtypes")
-	public AddToRepositoryMojoTest() throws NoSuchFieldException, IllegalAccessException {
-        factory = new DefaultArtifactFactory();
-        ArtifactHandlerManager artifactHandlerManager = new DefaultArtifactHandlerManager();
-        Field f = factory.getClass().getDeclaredField("artifactHandlerManager");
-        f.setAccessible(true);
-        f.set(factory, artifactHandlerManager);
-        f.setAccessible(false);
-
-        f = artifactHandlerManager.getClass().getDeclaredField("artifactHandlers");
-        f.setAccessible(true);
-        f.set(artifactHandlerManager, new HashMap());
-        f.setAccessible(false);
-    }
-
-    public void execute() throws MojoExecutionException, MojoFailureException {
-    }
-
-    @Test
-    public void testSimpleURL() throws Exception {
-        URL in = getClass().getClassLoader().getResource("input-repository.xml");
-        Repository repo = new Repository(in.toURI(), 80);
-
-        String[] repos = repo.getDefinedRepositories();
-
-        assert repos.length == 1;
-        assert repos[0].equals("http://foo.org");
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/8992a4fa/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/FeatureMetaDataExporterTest.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/FeatureMetaDataExporterTest.java b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/FeatureMetaDataExporterTest.java
deleted file mode 100644
index 3de0fcc..0000000
--- a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/FeatureMetaDataExporterTest.java
+++ /dev/null
@@ -1,78 +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 static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
-
-import javax.xml.stream.XMLStreamException;
-
-import org.apache.karaf.tooling.features.model.ArtifactRef;
-import org.apache.karaf.tooling.features.model.BundleRef;
-import org.apache.karaf.tooling.features.model.Feature;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.DefaultArtifact;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-import org.junit.Test;
-
-public class FeatureMetaDataExporterTest {
-
-    @Test
-    public void testWriteFeature() throws XMLStreamException, UnsupportedEncodingException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        FeatureMetaDataExporter featureMetaDataExporter = new FeatureMetaDataExporter(baos);
-        
-        BundleRef bundle = new BundleRef("mvn:org.apache.example/example/1.0.0", 10);
-        Artifact bundleArtifact = new DefaultArtifact("org.apache.example", "example", "1.0.0",
-                                                      null, "jar", null,
-                                                      new DefaultArtifactHandler());
-        bundle.setArtifact(bundleArtifact);
-
-        ArtifactRef configFile = new ArtifactRef("mvn:org.apache.example/example/1.0.0/cfg");
-        Artifact configFileArtifact = new DefaultArtifact("org.apache.example", "example", "1.0.0",
-                                                          null, "xml", "exampleconfig",
-                                                          new DefaultArtifactHandler());
-        configFile.setArtifact(configFileArtifact);
-
-        Feature feature = new Feature("example");
-        feature.addBundle(bundle);
-        feature.addConfigFile(configFile);
-
-        featureMetaDataExporter.writeFeature(feature);
-        featureMetaDataExporter.close();
-        
-        assertTrue(formatString(baos.toString("UTF-8")).contains(expectedValue()));
-    }
-
-    private String expectedValue() {
-        return formatString(
-              "<features>" +
-                   "<feature name=\"example\">" +
-                       "<bundle start-level=\"10\" name=\"example-1.0.0.jar\" groupId=\"org.apache.example\" artifactId=\"example\" type=\"jar\" version=\"1.0.0\">mvn:org.apache.example/example/1.0.0</bundle>" +
-                       "<config name=\"example-1.0.0-exampleconfig.xml\" groupId=\"org.apache.example\" artifactId=\"example\" type=\"xml\" classifier=\"exampleconfig\" version=\"1.0.0\">mvn:org.apache.example/example/1.0.0/cfg</config>" +
-                   "</feature>" +
-               "</features>");
-    }
-    
-    private String formatString(String string) {
-        return string.replaceAll("\n", "").replaceAll("\r", "");
-    }
-}