You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gg...@apache.org on 2017/06/21 13:27:20 UTC

[07/12] karaf git commit: [KARAF-5008] Initial "maven/core" module and first maven:summary command

[KARAF-5008] Initial "maven/core" module and first maven:summary command


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

Branch: refs/heads/master-maven-commands
Commit: 3ea2be24f2faf27892abaaf901aa4fa08242a61d
Parents: 5c2bb4b
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Mon Mar 13 15:42:53 2017 +0100
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 maven/core/pom.xml                              | 133 ++++++++
 .../command/MavenConfigurationSupport.java      | 298 ++++++++++++++++
 .../karaf/maven/command/RepoListCommand.java    |  70 ++++
 .../karaf/maven/command/SummaryCommand.java     | 100 ++++++
 .../karaf/maven/core/MavenRepositoryURL.java    | 338 +++++++++++++++++++
 .../src/main/resources/OSGI-INF/bundle.info     |  36 ++
 maven/pom.xml                                   |  40 +++
 pom.xml                                         |  11 +
 8 files changed, 1026 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/pom.xml
----------------------------------------------------------------------
diff --git a/maven/core/pom.xml b/maven/core/pom.xml
new file mode 100644
index 0000000..a05b3d1
--- /dev/null
+++ b/maven/core/pom.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf</groupId>
+        <artifactId>karaf</artifactId>
+        <version>4.1.1-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.karaf.maven</groupId>
+    <artifactId>org.apache.karaf.maven.core</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Maven :: Core</name>
+    <description>This bundle provides services and commands for Maven diagnostics.</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-aether</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-settings</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-settings-builder</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-embedder</artifactId>
+            <version>3.0.3</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*.info</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-services-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.karaf.maven
+                        </Export-Package>
+                        <Import-Package>
+                            !org.apache.maven*,
+                            !org.codehaus.plexus*,
+                            !org.sonatype.aether*,
+                            !org.sonatype.guice*,
+                            *,
+                        </Import-Package>
+                        <Private-Package>
+                            org.apache.karaf.maven.command,
+                            org.apache.karaf.maven.core,
+                            org.apache.maven.settings.*,
+                            org.apache.maven.execution,
+                            org.apache.maven.model,
+                            org.codehaus.plexus.component.annotations,
+                            org.sonatype.plexus.components.sec.dispatcher*,
+                            org.sonatype.plexus.components.cipher,
+                            org.codehaus.plexus.interpolation,
+                            org.codehaus.plexus.util,
+                            org.codehaus.plexus.util.xml,
+                            org.codehaus.plexus.util.xml.pull,
+                            org.codehaus.plexus.interpolation.os,
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
new file mode 100644
index 0000000..dbab04a
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -0,0 +1,298 @@
+/*
+ * 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.maven.command;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.building.DefaultSettingsBuilder;
+import org.apache.maven.settings.building.DefaultSettingsBuilderFactory;
+import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.apache.maven.settings.building.SettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsBuildingResult;
+import org.apache.maven.settings.building.SettingsProblem;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
+
+/**
+ * <p>Base class for <code>maven:</code> commands.</p>
+ * <p>Even if it duplicates some code from pax-url-aether, this should be treated as verification code of how
+ * pax-url-aether should interact with <code>org.ops4j.pax.url.mvn</code> PID configuration.</p>
+ */
+public abstract class MavenConfigurationSupport implements Action {
+
+    public static Logger LOG = LoggerFactory.getLogger(MavenConfigurationSupport.class);
+    protected static final String PID = "org.ops4j.pax.url.mvn";
+
+    static final String PROPERTY_LOCAL_REPOSITORY = "localRepository";
+    static final String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
+    static final String PROPERTY_REPOSITORIES = "repositories";
+    static final String PROPERTY_SETTINGS_FILE = "settings";
+
+    protected FileAndSource localRepository;
+    protected FileAndSource settings;
+    protected Settings effectiveSettings;
+    protected Map<String, String> serverPasswords = new HashMap<>();
+    protected Map<String, String> proxyPasswords = new HashMap<>();
+
+    protected List<String> warnings = new LinkedList<>();
+
+    @Reference
+    protected ConfigurationAdmin cm;
+
+    @Override
+    final public Object execute() throws Exception {
+        Configuration c = cm.getConfiguration(PID);
+
+        if (c != null && c.getProperties() != null) {
+            settings = settings((String) c.getProperties().get(PID + "." + PROPERTY_SETTINGS_FILE));
+            if (settings.file != null) {
+                reReadSettings(settings.file);
+            }
+            localRepository = localRepository((String) c.getProperties().get(PID + "." + PROPERTY_LOCAL_REPOSITORY));
+
+            doAction(PID + ".", c.getProperties());
+        } else {
+            System.err.printf("Can't access \"%s\" configuration\n", PID);
+        }
+
+        return null;
+    }
+
+    /**
+     * Performs command action on <strong>existing</strong> <code>org.ops4j.pax.url.mvn</code>
+     * PID configuration
+     * @param prefix
+     * @param config
+     */
+    abstract protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception;
+
+    /**
+     * Splits comma separated list of values into String array
+     * @param list
+     * @return
+     */
+    protected String[] listOfValues(String list) {
+        if (list == null) {
+            return new String[0];
+        }
+
+        String[] values = list.split("\\s*,\\s*");
+        return Arrays.stream(values)
+                .filter((value) -> (value != null && !"".equals(value.trim())))
+                .toArray(String[]::new);
+    }
+
+    /**
+     * Gets effective location of <code>settings.xml</code> file - according to pax-url-aether rules
+     * @param cmProperty property obtained from Config Admin
+     * @return
+     */
+    protected FileAndSource settings(String cmProperty) {
+        FileAndSource result = new FileAndSource();
+        URL locationUrl = null;
+        String probableErrorMessage = null;
+
+        // 1. PID + ".settings"
+        if (cmProperty != null && !"".equals(cmProperty.trim())) {
+            try {
+                locationUrl = new URL(cmProperty);
+                result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_SETTINGS_FILE);
+                probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
+                        locationUrl, PID, PROPERTY_SETTINGS_FILE);
+            } catch (MalformedURLException e) {
+                File file = new File(cmProperty);
+                if (file.isFile()) {
+                    result.file = file;
+                    result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_SETTINGS_FILE);
+                    return result;
+                }
+            }
+        }
+
+        // 2. System.getProperty("user.home") + "/.m2/settings.xml"
+        if (locationUrl == null) {
+            File file = new File(System.getProperty("user.home") + "/.m2/settings.xml");
+            if (file.isFile()) {
+                result.file = file;
+                result.source = "Implicit ${user.home}/.m2/settings.xml";
+                return result;
+            }
+        }
+
+        // 3. System.getProperty("maven.home") + "/conf/settings.xml"
+        if (locationUrl == null) {
+            File file = new File(System.getProperty("maven.home") + "/conf/settings.xml");
+            if (file.isFile()) {
+                result.file = file;
+                result.source = "Implicit ${maven.home}/conf/settings.xml";
+                return result;
+            }
+        }
+
+        // 4. System.getenv("M2_HOME") + "/conf/settings.xml"
+        if (locationUrl == null) {
+            File file = new File(System.getenv("M2_HOME") + "/conf/settings.xml");
+            if (file.isFile()) {
+                result.file = file;
+                result.source = "Implicit $M2_HOME/conf/settings.xml";
+                return result;
+            }
+        }
+
+        if (locationUrl != null) {
+            File file = new File(locationUrl.getPath());
+            if (file.isFile()) {
+                result.file = file;
+                return result;
+            } else {
+                throw new IllegalArgumentException(probableErrorMessage);
+            }
+        }
+
+        // 5. new org.apache.maven.settings.Settings()
+        return result;
+    }
+
+    /**
+     * Gets effective location of <em>local repository</em> - according to pax-url-aether rules
+     * @param cmProperty property obtained from Config Admin
+     * @return
+     */
+    protected FileAndSource localRepository(String cmProperty) {
+        FileAndSource result = new FileAndSource();
+        URL locationUrl = null;
+        String probableErrorMessage = null;
+
+        // 1. PID + ".localRepository"
+        if (cmProperty != null && !"".equals(cmProperty.trim())) {
+            try {
+                locationUrl = new URL(cmProperty);
+                result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
+                probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
+                        locationUrl, PID, PROPERTY_LOCAL_REPOSITORY);
+            } catch (MalformedURLException e) {
+                File file = new File(cmProperty);
+                if (file.isDirectory()) {
+                    result.file = file;
+                    result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
+                    return result;
+                }
+            }
+        }
+
+        // 2. from settings.xml
+        if (locationUrl == null && effectiveSettings != null && effectiveSettings.getLocalRepository() != null) {
+            try {
+                locationUrl = new URL(effectiveSettings.getLocalRepository());
+                result.source = String.format("Explicit <localRepository> in %s", settings.file);
+                probableErrorMessage = String.format("%s configured in %s is not accessible",
+                        effectiveSettings.getLocalRepository(), settings.file);
+            } catch (MalformedURLException e) {
+                File file = new File(effectiveSettings.getLocalRepository());
+                if (file.isDirectory()) {
+                    result.file = file;
+                    result.source = String.format("Explicit <localRepository> in %s", settings.file);
+                    return result;
+                }
+            }
+        }
+
+        // 3. System.getProperty("user.home") + "/.m2/repository";
+        if (locationUrl == null) {
+            File file = new File(System.getProperty("user.home") + "/.m2/repository");
+            if (file.isDirectory()) {
+                result.file = file;
+                result.source = "Implicit ${user.home}/.m2/repository";
+                return result;
+            }
+        }
+
+        if (locationUrl != null) {
+            File file = new File(locationUrl.getPath());
+            if (file.isDirectory()) {
+                result.file = file;
+                return result;
+            } else {
+                throw new IllegalArgumentException(probableErrorMessage);
+            }
+        }
+
+        // 5. new org.apache.maven.settings.Settings()
+        return null;
+    }
+
+    /**
+     * Re-reads on demand <code>settings.xml</code> file - with password decryption
+     * @param settingsFile
+     */
+    protected synchronized void reReadSettings(File settingsFile) throws SettingsBuildingException {
+        effectiveSettings = null;
+
+        if (!settingsFile.isFile() || !settingsFile.canRead()) {
+            throw new IllegalArgumentException(settingsFile + " is not accessible");
+        }
+
+        try {
+            DefaultSettingsBuilderFactory factory = new DefaultSettingsBuilderFactory();
+            DefaultSettingsBuilder builder = factory.newInstance();
+            SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
+            request.setUserSettingsFile(settingsFile);
+
+            SettingsBuildingResult result = builder.build(request);
+            if (result.getProblems().size() > 0) {
+                for (SettingsProblem problem : result.getProblems()) {
+                    System.err.println(problem);
+                }
+            } else {
+                effectiveSettings = result.getEffectiveSettings();
+                decryptSettings(effectiveSettings);
+            }
+        } catch (Throwable e) {
+            LOG.error(e.getMessage(), e);
+            throw e;
+        }
+    }
+
+    /**
+     * Decrypts passwords inside <code>&lt;proxy&gt;</code> and <code>&lt;repository&gt;</code>
+     * @param settings
+     */
+    private void decryptSettings(Settings settings) {
+        String masterMasterPassword = DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION;
+    }
+
+    protected static class FileAndSource  {
+        File file;
+        String source;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
new file mode 100644
index 0000000..02195e1
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.maven.command;
+
+import java.net.MalformedURLException;
+import java.util.Dictionary;
+
+import org.apache.karaf.maven.core.MavenRepositoryURL;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "maven", name = "repo-list", description = "Maven repository summary.")
+@Service
+public class RepoListCommand extends MavenConfigurationSupport {
+
+    @Override
+    public void doAction(String prefix, Dictionary<String, Object> config) throws MalformedURLException {
+        ShellTable table = new ShellTable();
+        table.column("ID");
+        table.column("URL");
+        table.column("Snapshots");
+        table.column("Releases");
+
+        System.out.println("== Remote repositories");
+        String[] repositories = listOfValues((String) config.get(prefix + PROPERTY_REPOSITORIES));
+        for (String repo : repositories) {
+            MavenRepositoryURL repoURL = new MavenRepositoryURL(repo);
+            table.addRow().addContent(repoURL.getId(),
+                    repoURL.getURL(),
+                    repoURL.isSnapshotsEnabled() ? "yes" : "no",
+                    repoURL.isReleasesEnabled() ? "yes" : "no");
+        }
+
+        table.print(System.out);
+
+        table = new ShellTable();
+        table.column("ID");
+        table.column("URL");
+        table.column("Snapshots");
+        table.column("Releases");
+        System.out.println();
+        System.out.println("== Default repositories");
+        repositories = listOfValues((String) config.get(prefix + PROPERTY_DEFAULT_REPOSITORIES));
+        for (String repo : repositories) {
+            MavenRepositoryURL repoURL = new MavenRepositoryURL(repo);
+            table.addRow().addContent(repoURL.getId(),
+                    repoURL.getURL(),
+                    repoURL.isSnapshotsEnabled() ? "yes" : "no",
+                    repoURL.isReleasesEnabled() ? "yes" : "no");
+        }
+
+        table.print(System.out);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
new file mode 100644
index 0000000..0e791cd
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -0,0 +1,100 @@
+/*
+ * 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.maven.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.Col;
+import org.apache.karaf.shell.support.table.Row;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "maven", name = "summary", description = "Maven configuration summary.")
+@Service
+public class SummaryCommand extends MavenConfigurationSupport {
+
+    @Option(name = "-d", aliases = { "--description" }, description = "Adds description of Maven configuration options", required = false, multiValued = false)
+    boolean description;
+
+    /*
+     * All options from org.ops4j.pax.url.mvn.ServiceConstants (2.5.2):
+     *
+     * String PROPERTY_LOCAL_REPOSITORY = "localRepository";
+     * String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
+     * String PROPERTY_REPOSITORIES = "repositories";
+     * String PROPERTY_SETTINGS_FILE = "settings";
+     * String REQUIRE_CONFIG_ADMIN_CONFIG = "requireConfigAdminConfig";
+     * String PROPERTY_GLOBAL_UPDATE_POLICY = "globalUpdatePolicy";
+     * String PROPERTY_GLOBAL_CHECKSUM_POLICY = "globalChecksumPolicy";
+     * String PROPERTY_UPDATE_RELEASES = "updateReleases";
+     * String PROPERTY_LOCAL_REPO_AS_REMOTE = "defaultLocalRepoAsRemote";
+     * String PROPERTY_CERTIFICATE_CHECK = "certificateCheck";
+     * String PROPERTY_USE_FALLBACK_REPOSITORIES = "useFallbackRepositories";
+     * String PROPERTY_PROXY_SUPPORT = "proxySupport";
+     * String PROPERTY_SECURITY = "security";
+     * String PROPERTY_TIMEOUT = "timeout";
+     * String PROPERTY_OFFLINE = "offline";
+     * String PROPERTY_PROXIES = "proxies";
+     * String PROPERTY_SOCKET_SO_TIMEOUT = "socket.readTimeout";
+     * String PROPERTY_SOCKET_SO_KEEPALIVE = "socket.keepAlive";
+     * String PROPERTY_SOCKET_SO_LINGER = "socket.linger";
+     * String PROPERTY_SOCKET_SO_REUSEADDRESS = "socket.reuseAddress";
+     * String PROPERTY_SOCKET_TCP_NODELAY = "socket.tcpNoDelay";
+     * String PROPERTY_SOCKET_CONNECTION_TIMEOUT = "socket.connectionTimeout";
+     * String PROPERTY_CONNECTION_BUFFER_SIZE = "connection.bufferSize";
+     * String PROPERTY_CONNECTION_RETRY_COUNT = "connection.retryCount";
+     *
+     * String OPTION_ALLOW_SNAPSHOTS = "snapshots";
+     * String OPTION_DISALLOW_RELEASES = "noreleases";
+     * String OPTION_MULTI = "multi";
+     * String OPTION_ID = "id";
+     * String OPTION_UPDATE = "update";
+     * String OPTION_RELEASES_UPDATE = "releasesUpdate";
+     * String OPTION_SNAPSHOTS_UPDATE = "snapshotsUpdate";
+     * String OPTION_CHECKSUM = "checksum";
+     * String OPTION_RELEASES_CHECKSUM = "releasesChecksum";
+     * String OPTION_SNAPSHOTS_CHECKSUM = "snapshotsChecksum";
+     */
+
+    @Override
+    protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
+        ShellTable table = new ShellTable();
+        table.column(new Col("Option").alignRight());
+        table.column("Value");
+        table.column("Source");
+        if (description) {
+            table.column("Description");
+        }
+
+        Row row = table.addRow();
+        row.addContent("Local repository", localRepository.file, localRepository.source);
+        if (description) {
+            row.addContent("Maven repository to store artifacts resolved in *remote repositories*");
+        }
+
+        row = table.addRow();
+        row.addContent("Settings file", settings.file, settings.source);
+        if (description) {
+            row.addContent("Settings file that may contain configuration of additional repositories, http proxies and mirrors");
+        }
+
+        table.print(System.out);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
new file mode 100644
index 0000000..858f85e
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2008 Alin Dreghiciu.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.maven.core;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.ops4j.pax.url.mvn.ServiceConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An URL of Maven repository that knows if it contains SNAPSHOT versions and/or releases.
+ *
+ * @author Alin Dreghiciu
+ * @author Guillaume Nodet
+ * @since 0.2.1, February 07, 2008
+ */
+public class MavenRepositoryURL
+{
+
+    private static final Logger LOG = LoggerFactory.getLogger( MavenRepositoryURL.class );
+
+    /**
+     * Repository Id.
+     */
+    private final String m_id;
+    /**
+     * Repository URL.
+     */
+    private final URL m_repositoryURL;
+    /**
+     * Repository file (only if URL is a file URL).
+     */
+    private final File m_file;
+    /**
+     * True if the repository contains snapshots.
+     */
+    private final boolean m_snapshotsEnabled;
+    /**
+     * True if the repository contains releases.
+     */
+    private final boolean m_releasesEnabled;
+    /**
+     * Repository update policy
+     */
+    private final String m_releasesUpdatePolicy;
+    /**
+     * Repository update policy
+     */
+    private final String m_snapshotsUpdatePolicy;
+    /**
+     * Repository checksum policy
+     */
+    private final String m_releasesChecksumPolicy;
+    /**
+     * Repository checksum policy
+     */
+    private final String m_snapshotsChecksumPolicy;
+
+    private final boolean m_multi;
+
+    /**
+     * Creates a maven repository URL bases on a string spec. The path can be marked with @snapshots and/or @noreleases
+     * (not case sensitive).
+     *
+     * @param repositorySpec url spec of repository
+     *
+     * @throws MalformedURLException if spec contains a malformed maven repository url
+     */
+    public MavenRepositoryURL( final String repositorySpec )
+        throws MalformedURLException
+    {
+        final String[] segments = repositorySpec.split( ServiceConstants.SEPARATOR_OPTIONS );
+        final StringBuilder urlBuilder = new StringBuilder();
+        boolean snapshotEnabled = false;
+        boolean releasesEnabled = true;
+        boolean multi = false;
+
+        String name = null;
+        String update = null;
+        String updateReleases = null;
+        String updateSnapshots = null;
+        String checksum = null;
+        String checksumReleases = null;
+        String checksumSnapshots = null;
+
+        for( int i = 0; i < segments.length; i++ )
+        {
+            String segment = segments[i].trim();
+            if( segment.equalsIgnoreCase( ServiceConstants.OPTION_ALLOW_SNAPSHOTS ) )
+            {
+                snapshotEnabled = true;
+            }
+            else if( segment.equalsIgnoreCase( ServiceConstants.OPTION_DISALLOW_RELEASES ) )
+            {
+                releasesEnabled = false;
+            }
+            else if( segment.equalsIgnoreCase( ServiceConstants.OPTION_MULTI ) )
+            {
+                multi = true;
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_ID + "=" ) )
+            {
+                try {
+                    name = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_RELEASES_UPDATE + "=" ) )
+            {
+                try {
+                    updateReleases = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_SNAPSHOTS_UPDATE + "=" ) )
+            {
+                try {
+                    updateSnapshots = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_UPDATE + "=" ) )
+            {
+                try {
+                    update = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_RELEASES_CHECKSUM + "=" ) )
+            {
+                try {
+                    checksumReleases = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_SNAPSHOTS_CHECKSUM + "=" ) )
+            {
+                try {
+                    checksumSnapshots = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_CHECKSUM + "=" ) )
+            {
+                try {
+                    checksum = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else
+            {
+                if( i > 0 )
+                {
+                    urlBuilder.append( ServiceConstants.SEPARATOR_OPTIONS );
+                }
+                urlBuilder.append( segments[ i ] );
+            }
+        }
+        String spec = buildSpec( urlBuilder );
+        m_repositoryURL = new URL( spec );
+        m_snapshotsEnabled = snapshotEnabled;
+        m_releasesEnabled = releasesEnabled;
+        m_multi = multi;
+        if (name == null) {
+            String warn = "Repository spec " + spec + " does not contain an identifier. This is deprecated & discouraged & just evil.";
+            LOG.warn( warn );
+            name = "repo_" + spec.hashCode();
+        }
+        m_id = name;
+        m_releasesUpdatePolicy = updateReleases != null ? updateReleases : update;
+        m_snapshotsUpdatePolicy = updateSnapshots != null ? updateSnapshots : update;
+        m_releasesChecksumPolicy = checksumReleases != null ? checksumReleases : checksum;
+        m_snapshotsChecksumPolicy = checksumSnapshots != null ? checksumSnapshots : checksum;
+
+        if( m_repositoryURL.getProtocol().equals( "file" ) )
+        {
+            try
+            {
+                // You must transform to URI to decode the path (manage a path with a space or non
+                // us character)
+                // like D:/documents%20and%20Settings/SESA170017/.m2/repository
+                // the path can be store in path part or in scheme specific part (if is relatif
+                // path)
+                // the anti-slash character is not a valid character for uri.
+                spec = spec.replaceAll( "\\\\", "/" );
+                spec = spec.replaceAll( " ", "%20" );
+                URI uri = new URI( spec );
+                String path = uri.getPath();
+                if( path == null )
+                    path = uri.getSchemeSpecificPart();
+                m_file = new File( path );
+
+            }
+            catch ( URISyntaxException e )
+            {
+                throw new MalformedURLException( e.getMessage() );
+            }
+        }
+        else
+        {
+            m_file = null;
+        }
+    }
+
+    private String buildSpec( StringBuilder urlBuilder )
+    {
+        String spec = urlBuilder.toString().trim();
+        if( !spec.endsWith( "\\" ) && !spec.endsWith( "/" ) )
+        {
+            spec = spec + "/";
+        }
+        return spec;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return repository id
+     */
+    public String getId()
+    {
+        return m_id;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return repository URL
+     */
+    public URL getURL()
+    {
+        return m_repositoryURL;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return repository file
+     */
+    public File getFile()
+    {
+        return m_file;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return true if the repository contains releases
+     */
+    public boolean isReleasesEnabled()
+    {
+        return m_releasesEnabled;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return true if the repository contains snapshots
+     */
+    public boolean isSnapshotsEnabled()
+    {
+        return m_snapshotsEnabled;
+    }
+
+    public String getReleasesUpdatePolicy() {
+        return m_releasesUpdatePolicy;
+    }
+
+    public String getSnapshotsUpdatePolicy() {
+        return m_snapshotsUpdatePolicy;
+    }
+
+    public String getReleasesChecksumPolicy() {
+        return m_releasesChecksumPolicy;
+    }
+
+    public String getSnapshotsChecksumPolicy() {
+        return m_snapshotsChecksumPolicy;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return true if the repository is a parent path of repos
+     */
+    public boolean isMulti()
+    {
+        return m_multi;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return if the repository is a file based repository.
+     */
+    public boolean isFileRepository()
+    {
+        return m_file != null;
+    }
+
+    @Override
+    public String toString()
+    {
+        return new StringBuilder()
+            .append( m_repositoryURL.toString() )
+            .append( ",releases=" ).append( m_releasesEnabled )
+            .append( ",snapshots=" ).append( m_snapshotsEnabled )
+            .toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/maven/core/src/main/resources/OSGI-INF/bundle.info b/maven/core/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..509e13b
--- /dev/null
+++ b/maven/core/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,36 @@
+#
+#
+#    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.
+#
+#
+h1. Synopsis
+
+	${project.name}
+
+	${project.description}
+
+	Maven URL:
+		[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+	This bundle is the core implementation of Maven diagnostics support and exposes commands
+	to change and examine Maven configuration managed by pax-url-aether bundle and org.ops4j.pax.url.mvn PID.
+
+h1. Commands
+
+	The bundle contains the following commands:
+\${command-list|maven|indent=8,list,cyan}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/pom.xml
----------------------------------------------------------------------
diff --git a/maven/pom.xml b/maven/pom.xml
new file mode 100644
index 0000000..a8d8369
--- /dev/null
+++ b/maven/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf</groupId>
+        <artifactId>karaf</artifactId>
+        <version>4.1.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.karaf.maven</groupId>
+    <artifactId>maven-parent</artifactId>
+    <packaging>pom</packaging>
+    <name>Apache Karaf :: Maven</name>
+
+    <modules>
+        <module>core</module>
+    </modules>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a7367d2..2767cb1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,6 +65,7 @@
         <module>jdbc</module>
         <module>jms</module>
         <module>jpa</module>
+        <module>maven</module>
         <module>services</module>
         <module>subsystem</module>
         <module>profile</module>
@@ -1077,6 +1078,16 @@
                 <version>${maven.version}</version>
             </dependency>
             <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-settings</artifactId>
+                <version>${maven.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-settings-builder</artifactId>
+                <version>${maven.version}</version>
+            </dependency>
+            <dependency>
                 <groupId>org.apache.maven.shared</groupId>
                 <artifactId>maven-dependency-tree</artifactId>
                 <version>2.2</version>