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 2014/04/10 16:15:45 UTC

[23/59] [abbrv] [KARAF-2852] Merge config/core and config/command

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/core/src/main/java/org/apache/karaf/config/core/impl/ConfigMBeanImpl.java
----------------------------------------------------------------------
diff --git a/config/core/src/main/java/org/apache/karaf/config/core/impl/ConfigMBeanImpl.java b/config/core/src/main/java/org/apache/karaf/config/core/impl/ConfigMBeanImpl.java
deleted file mode 100644
index a8b8090..0000000
--- a/config/core/src/main/java/org/apache/karaf/config/core/impl/ConfigMBeanImpl.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.config.core.impl;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
-import javax.management.MBeanException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.StandardMBean;
-
-import org.apache.karaf.config.core.ConfigMBean;
-import org.apache.karaf.config.core.ConfigRepository;
-import org.osgi.service.cm.Configuration;
-
-/**
- * Implementation of the ConfigMBean.
- */
-public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean {
-
-    private ConfigRepository configRepo;
-
-    public ConfigMBeanImpl() throws NotCompliantMBeanException {
-        super(ConfigMBean.class);
-    }
-
-    private Configuration getConfiguration(String pid) throws IOException {
-        Configuration configuration = configRepo.getConfigAdmin().getConfiguration(pid);
-        if (configuration == null) {
-            throw new IllegalArgumentException("Configuration PID " + pid + " doesn't exist");
-        }
-        return configuration;
-    }
-
-    @SuppressWarnings("rawtypes")
-    private Dictionary getConfigProperties(String pid) throws IOException {
-        Configuration configuration = getConfiguration(pid);
-
-        Dictionary dictionary = configuration.getProperties();
-        if (dictionary == null) {
-            dictionary = new java.util.Properties();
-        }
-        return dictionary;
-    }
-
-    /**
-     * Get all config pids
-     */
-    public List<String> getConfigs() throws MBeanException {
-        try {
-            Configuration[] configurations = this.configRepo.getConfigAdmin().listConfigurations(null);
-            List<String> pids = new ArrayList<String>();
-            for (int i = 0; i < configurations.length; i++) {
-                pids.add(configurations[i].getPid());
-            }
-            return pids;
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @SuppressWarnings("rawtypes")
-    public void create(String pid) throws MBeanException {
-        try {
-            configRepo.update(pid, new Hashtable());
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    public void delete(String pid) throws MBeanException {
-        try {
-            this.configRepo.delete(pid);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @SuppressWarnings("rawtypes")
-    public Map<String, String> listProperties(String pid) throws MBeanException {
-        try {
-            Dictionary dictionary = getConfigProperties(pid);
-
-            Map<String, String> propertiesMap = new HashMap<String, String>();
-            for (Enumeration e = dictionary.keys(); e.hasMoreElements(); ) {
-                Object key = e.nextElement();
-                Object value = dictionary.get(key);
-                propertiesMap.put(key.toString(), value.toString());
-            }
-            return propertiesMap;
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @SuppressWarnings("rawtypes")
-    public void deleteProperty(String pid, String key) throws MBeanException {
-        try {
-            Dictionary dictionary = getConfigProperties(pid);
-            dictionary.remove(key);
-            configRepo.update(pid, dictionary);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @SuppressWarnings({"rawtypes", "unchecked"})
-    public void appendProperty(String pid, String key, String value) throws MBeanException {
-        try {
-            Dictionary dictionary = getConfigProperties(pid);
-            Object currentValue = dictionary.get(key);
-            if (currentValue == null) {
-                dictionary.put(key, value);
-            } else if (currentValue instanceof String) {
-                dictionary.put(key, currentValue + value);
-            } else {
-                throw new IllegalStateException("Current value is not a String");
-            }
-            configRepo.update(pid, dictionary);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @SuppressWarnings({"rawtypes", "unchecked"})
-    public void setProperty(String pid, String key, String value) throws MBeanException {
-        try {
-            Dictionary dictionary = getConfigProperties(pid);
-            dictionary.put(key, value);
-            configRepo.update(pid, dictionary);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    public void update(String pid, Map<String, String> properties) throws MBeanException {
-        try {
-            if (properties == null) {
-                properties = new HashMap<String, String>();
-            }
-            Dictionary<String, String> dictionary = toDictionary(properties);
-            configRepo.update(pid, dictionary);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-	private Dictionary<String, String> toDictionary(
-			Map<String, String> properties) {
-		Dictionary<String, String> dictionary = new Hashtable<String, String>();
-		for (String key : properties.keySet()) {
-		    dictionary.put(key, properties.get(key));
-		}
-		return dictionary;
-	}
-
-
-    public void setConfigRepo(ConfigRepository configRepo) {
-        this.configRepo = configRepo;
-    }
-
-	@Override
-	public String createFactoryConfiguration(String factoryPid,
-			Map<String, String> properties) throws MBeanException {
-		Dictionary<String, String> dict = toDictionary(properties);
-		return configRepo.createFactoryConfiguration(factoryPid, dict);
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/core/src/main/java/org/apache/karaf/config/core/impl/ConfigRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/config/core/src/main/java/org/apache/karaf/config/core/impl/ConfigRepositoryImpl.java b/config/core/src/main/java/org/apache/karaf/config/core/impl/ConfigRepositoryImpl.java
deleted file mode 100644
index 11bb720..0000000
--- a/config/core/src/main/java/org/apache/karaf/config/core/impl/ConfigRepositoryImpl.java
+++ /dev/null
@@ -1,99 +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.config.core.impl;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.karaf.config.core.ConfigRepository;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-
-public class ConfigRepositoryImpl implements ConfigRepository {
-    private ConfigurationAdmin configAdmin;
-    
-    private File storage;
-
-    public ConfigRepositoryImpl(ConfigurationAdmin configAdmin) {
-        this.configAdmin = configAdmin;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.karaf.shell.config.impl.ConfigRepository#update(java.lang.String, java.util.Dictionary, boolean)
-     */
-    @Override
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public void update(String pid, Dictionary props) throws IOException {
-        Configuration cfg = this.configAdmin.getConfiguration(pid, null);
-        if (cfg.getBundleLocation() != null) {
-            cfg.setBundleLocation(null);
-        }
-        cfg.update(props);
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.karaf.shell.config.impl.ConfigRepository#delete(java.lang.String)
-     */
-    @Override
-    public void delete(String pid) throws Exception {
-        Configuration configuration = this.configAdmin.getConfiguration(pid);
-        configuration.delete();
-        deleteStorage(pid);
-    }
-    
-    protected void deleteStorage(String pid) throws Exception {
-        if (storage != null) {
-            File cfgFile = new File(storage, pid + ".cfg");
-            cfgFile.delete();
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.karaf.shell.config.impl.ConfigRepository#getConfigProperties(java.lang.String)
-     */
-    @Override
-    @SuppressWarnings("rawtypes")
-    public Dictionary getConfigProperties(String pid) throws IOException, InvalidSyntaxException {
-        if(pid != null && configAdmin != null) {
-            Configuration configuration = this.configAdmin.getConfiguration(pid);
-            if(configuration != null) {
-                Dictionary props = configuration.getProperties();
-                return (props != null) ? props : new Hashtable<String, String>();
-            }
-        }
-        return null;
-    }
-
-    public ConfigurationAdmin getConfigAdmin() {
-        return this.configAdmin;
-    }
-
-	@Override
-	public String createFactoryConfiguration(String factoryPid, Dictionary<String, ?> properties) {
-		try {
-			Configuration config = configAdmin.createFactoryConfiguration(factoryPid);
-			config.update(properties);
-			return config.getPid();
-		} catch (IOException e) {
-			throw new RuntimeException(e.getMessage(), e);
-		}
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/core/src/main/java/org/apache/karaf/config/core/impl/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/config/core/src/main/java/org/apache/karaf/config/core/impl/osgi/Activator.java b/config/core/src/main/java/org/apache/karaf/config/core/impl/osgi/Activator.java
deleted file mode 100644
index bdfab09..0000000
--- a/config/core/src/main/java/org/apache/karaf/config/core/impl/osgi/Activator.java
+++ /dev/null
@@ -1,46 +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.config.core.impl.osgi;
-
-import org.apache.karaf.config.core.ConfigRepository;
-import org.apache.karaf.config.core.impl.ConfigMBeanImpl;
-import org.apache.karaf.config.core.impl.ConfigRepositoryImpl;
-import org.apache.karaf.util.tracker.BaseActivator;
-import org.osgi.service.cm.ConfigurationAdmin;
-
-public class Activator extends BaseActivator {
-
-    @Override
-    protected void doOpen() throws Exception {
-        trackService(ConfigurationAdmin.class);
-    }
-
-    protected void doStart() throws Exception {
-        ConfigurationAdmin configurationAdmin = getTrackedService(ConfigurationAdmin.class);
-        if (configurationAdmin == null) {
-            return;
-        }
-
-        ConfigRepository configRepository = new ConfigRepositoryImpl(configurationAdmin);
-        register(ConfigRepository.class, configRepository);
-
-        ConfigMBeanImpl configMBean = new ConfigMBeanImpl();
-        configMBean.setConfigRepo(configRepository);
-        registerMBean(configMBean, "type=config");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/core/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/config/core/src/main/resources/OSGI-INF/bundle.info b/config/core/src/main/resources/OSGI-INF/bundle.info
deleted file mode 100644
index 3cd35da..0000000
--- a/config/core/src/main/resources/OSGI-INF/bundle.info
+++ /dev/null
@@ -1,27 +0,0 @@
-h1. Synopsis
-
-${project.name}
-
-${project.description}
-
-Maven URL:
-[mvn:${project.groupId}/${project.artifactId}/${project.version}]
-
-h1. Description
-
-This bundle provides Karaf shell commands to manipulate the ConfigAdmin OSGi service.
-
-The following commands are available:
-* config:cancel - Cancels the changes to the configuration being edited.
-* config:edit - Creates or edits a configuration.
-* config:list - Lists existing configurations.
-* config:propappend - Appends the given value to an existing property or creates
- the property with the specified name and value.
-* config:propdel - Deletes a property from the edited configuration.
-* config:proplist - Lists properties from the currently edited configuration.
-* config:propset - Sets a property in the currently edited configuration.
-* config:update - Saves and propagates changes from the configuration being edited.
-
-h1. See also
-
-Commands - section of the Karaf User Guide.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/core/src/main/resources/OSGI-INF/metatype/metatype.properties
----------------------------------------------------------------------
diff --git a/config/core/src/main/resources/OSGI-INF/metatype/metatype.properties b/config/core/src/main/resources/OSGI-INF/metatype/metatype.properties
deleted file mode 100644
index 3bce187..0000000
--- a/config/core/src/main/resources/OSGI-INF/metatype/metatype.properties
+++ /dev/null
@@ -1,28 +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.
-#
-
-#
-# This file contains localization strings for configuration labels and
-# descriptions as used in the metatype.xml descriptor
-
-config.name = Apache Karaf Shell Config
-config.description = Configuration of Apache Karaf Shell Config
-
-storage.name = Storage directory
-storage.description = the directory used as a storage for configurations

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/core/src/main/resources/OSGI-INF/metatype/metatype.xml
----------------------------------------------------------------------
diff --git a/config/core/src/main/resources/OSGI-INF/metatype/metatype.xml b/config/core/src/main/resources/OSGI-INF/metatype/metatype.xml
deleted file mode 100644
index 83d3242..0000000
--- a/config/core/src/main/resources/OSGI-INF/metatype/metatype.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    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.
-
--->
-<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0" localization="OSGI-INF/metatype/metatype">
-    <OCD id="org.apache.karaf.config" name="%config.name" description="%config.description">
-        <AD id="storage" type="String" default="${karaf.etc}/"
-            name="%storage.name" description="%storage.description"/>
-    </OCD>
-    <Designate pid="org.apache.karaf.config">
-        <Object ocdref="org.apache.karaf.config"/>
-    </Designate>
-</metatype:MetaData>

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/pom.xml
----------------------------------------------------------------------
diff --git a/config/pom.xml b/config/pom.xml
index 10cc1af..af0de85 100644
--- a/config/pom.xml
+++ b/config/pom.xml
@@ -10,7 +10,7 @@
         (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
+           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,
@@ -29,13 +29,92 @@
     </parent>
 
     <groupId>org.apache.karaf.config</groupId>
-    <artifactId>config</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Karaf :: ConfigAdmin</name>
-
-    <modules>
-        <module>core</module>
-        <module>command</module>
-    </modules>
+    <artifactId>org.apache.karaf.config.core</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: ConfigAdmin :: Core</name>
+    <description>This bundle provides Karaf services</description>
+
+    <properties>
+        <appendedResourcesDirectory>${basedir}/../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
+
+    <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.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
+            <scope>test</scope>
+        </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.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.karaf.config.command*,
+                            org.apache.karaf.config.core
+                        </Export-Package>
+                        <Import-Package>
+                            *
+                        </Import-Package>
+                        <Private-Package>
+                            org.apache.karaf.config.core.impl,
+                            org.apache.karaf.config.core.impl.osgi,
+                            org.apache.karaf.util.tracker
+                        </Private-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.config.core.impl.osgi.Activator
+                        </Bundle-Activator>
+                        <Karaf-Commands>org.apache.karaf.config.command.*</Karaf-Commands>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 
 </project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/CancelCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/CancelCommand.java b/config/src/main/java/org/apache/karaf/config/command/CancelCommand.java
new file mode 100644
index 0000000..dff43fa
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/CancelCommand.java
@@ -0,0 +1,32 @@
+/*
+ * 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.config.command;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "config", name = "cancel", description = "Cancels the changes to the configuration being edited.")
+@Service
+public class CancelCommand extends ConfigCommandSupport {
+
+    protected Object doExecute() throws Exception {
+        session.put(PROPERTY_CONFIG_PID, null);
+        session.put(PROPERTY_CONFIG_PROPS, null);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java b/config/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java
new file mode 100644
index 0000000..fe0ca93
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java
@@ -0,0 +1,63 @@
+/*
+ * 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.config.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.config.core.ConfigRepository;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.console.Session;
+
+/**
+ * Abstract class from which all commands related to the ConfigurationAdmin
+ * service should derive.
+ * This command retrieves a reference to the ConfigurationAdmin service before
+ * calling another method to actually process the command.
+ */
+public abstract class ConfigCommandSupport implements Action {
+
+    public static final String PROPERTY_CONFIG_PID = "ConfigCommand.PID";
+    public static final String PROPERTY_CONFIG_PROPS = "ConfigCommand.Props";
+    public static final String PROPERTY_FACTORY = "ConfigCommand.Factory";
+
+    @Reference
+    protected ConfigRepository configRepository;
+
+    @Reference
+    protected Session session;
+
+    @Override
+    public Object execute() throws Exception {
+        return doExecute();
+    }
+
+    protected abstract Object doExecute() throws Exception;
+
+    @SuppressWarnings("rawtypes")
+    protected Dictionary getEditedProps() throws Exception {
+        return (Dictionary) this.session.get(PROPERTY_CONFIG_PROPS);
+    }
+    
+    public void setConfigRepository(ConfigRepository configRepository) {
+        this.configRepository = configRepository;
+    }
+
+    public void setSession(Session session) {
+        this.session = session;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/ConfigPropertyCommandSupport.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/ConfigPropertyCommandSupport.java b/config/src/main/java/org/apache/karaf/config/command/ConfigPropertyCommandSupport.java
new file mode 100644
index 0000000..619c224
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/ConfigPropertyCommandSupport.java
@@ -0,0 +1,85 @@
+/*
+ * 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.config.command;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.apache.karaf.config.command.completers.ConfigurationCompleter;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+
+/**
+ * Abstract class which commands that are related to property processing should extend.
+ */
+public abstract class ConfigPropertyCommandSupport extends ConfigCommandSupport {
+
+    @Option(name = "-p", aliases = "--pid", description = "The configuration pid", required = false, multiValued = false)
+    @Completion(ConfigurationCompleter.class)
+    protected String pid;
+
+    @SuppressWarnings("rawtypes")
+    protected Object doExecute() throws Exception {
+        Dictionary props = getEditedProps();
+        if (props == null && pid == null) {
+            System.err.println("No configuration is being edited--run the edit command first");
+        } else {
+            if (props == null) {
+                props = new Properties();
+            }
+            propertyAction(props);
+            if(requiresUpdate(pid)) {
+                this.configRepository.update(pid, props);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Perform an action on the properties.
+     * @param props
+     */
+    @SuppressWarnings("rawtypes")
+    protected abstract void propertyAction(Dictionary props);
+
+    /**
+     * Checks if the configuration requires to be updated.
+     * The default behavior is to update if a valid pid has been passed to the method.
+     * @param pid
+     * @return
+     */
+    protected boolean requiresUpdate(String pid) {
+        if (pid != null) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Retrieves confguration from the pid, if used or delegates to session from getting the configuration.
+     * @return
+     * @throws Exception
+     */
+    @SuppressWarnings("rawtypes")
+    @Override
+    protected Dictionary getEditedProps() throws Exception {
+        Dictionary props = this.configRepository.getConfigProperties(pid);
+        return (props != null) ? props : super.getEditedProps();
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/DeleteCommand.java b/config/src/main/java/org/apache/karaf/config/command/DeleteCommand.java
new file mode 100644
index 0000000..6953ef0
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/DeleteCommand.java
@@ -0,0 +1,52 @@
+/*
+ * 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.config.command;
+
+import org.apache.karaf.config.command.completers.ConfigurationCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "config", name = "delete", description = "Delete a configuration.")
+@Service
+public class DeleteCommand extends ConfigCommandSupport {
+
+    @Argument(index = 0, name = "pid", description = "PID of the configuration", required = true, multiValued = false)
+    @Completion(ConfigurationCompleter.class)
+    String pid;
+
+    @Option(name = "--force", aliases = {}, description = "Force the edition of this config, even if another one was under edition", required = false, multiValued = false)
+    boolean force;
+
+    protected Object doExecute() throws Exception {
+        String oldPid = (String) this.session.get(PROPERTY_CONFIG_PID);
+        if (oldPid != null && oldPid.equals(pid) && !force) {
+            System.err.println("This config is being edited.  Cancel / update first, or use the --force option");
+            return null;
+        }
+
+        this.configRepository.delete(pid);
+        if (oldPid != null && oldPid.equals(pid) && !force) {
+            this.session.put(PROPERTY_CONFIG_PID, null);
+            this.session.put(PROPERTY_CONFIG_PROPS, null);
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/EditCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/EditCommand.java b/config/src/main/java/org/apache/karaf/config/command/EditCommand.java
new file mode 100644
index 0000000..8c48b83
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/EditCommand.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.config.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.config.command.completers.ConfigurationCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.osgi.service.cm.Configuration;
+
+@Command(scope = "config", name = "edit", description = "Creates or edits a configuration.", detailedDescription="classpath:edit.txt")
+@Service
+public class EditCommand extends ConfigCommandSupport {
+
+    @Argument(index = 0, name = "pid", description = "PID of the configuration or of the factory if --factory is given. Pid can also be specified as ldap query", required = true, multiValued = false)
+    @Completion(ConfigurationCompleter.class)
+    String pid;
+
+    @Option(name = "--force", aliases = {}, description = "Force the edition of this config, even if another one was under edition", required = false, multiValued = false)
+    boolean force;
+    
+    @Option(name = "--factory", aliases = {}, description = "Define this config as a factory config. Will be crearted on calling update", required = false, multiValued = false)
+    boolean factory;
+
+    @SuppressWarnings("rawtypes")
+    protected Object doExecute() throws Exception {
+        String oldPid = (String) this.session.get(PROPERTY_CONFIG_PID);
+        if (oldPid != null && !oldPid.equals(pid) && !force) {
+            System.err.println("Another config is being edited.  Cancel / update first, or use the --force option");
+            return null;
+        }
+        
+        if (pid.startsWith("(")) {
+        	Configuration[] configs = this.configRepository.getConfigAdmin().listConfigurations(pid);
+        	if (configs.length == 0) {
+        		throw new RuntimeException("Filter matches no config");
+        	}
+        	if (configs.length > 1) {
+        		throw new RuntimeException("Filter matches more than one config");
+        	}
+        	pid = configs[0].getPid();
+        	System.out.println("Editing config " + pid);
+        }
+
+        Dictionary props = this.configRepository.getConfigProperties(pid);
+        this.session.put(PROPERTY_CONFIG_PID, pid);
+        this.session.put(PROPERTY_FACTORY, factory);
+        this.session.put(PROPERTY_CONFIG_PROPS, props);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/ListCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/ListCommand.java b/config/src/main/java/org/apache/karaf/config/command/ListCommand.java
new file mode 100644
index 0000000..bce8410
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/ListCommand.java
@@ -0,0 +1,68 @@
+/*
+ * 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.config.command;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.osgi.service.cm.Configuration;
+
+@Command(scope = "config", name = "list", description = "Lists existing configurations.")
+@Service
+public class ListCommand extends ConfigCommandSupport {
+
+    @Argument(index = 0, name = "query", description = "Query in LDAP syntax. Example: \"(service.pid=org.apache.karaf.log)\"", required = false, multiValued = false)
+    String query;
+
+    @SuppressWarnings("rawtypes")
+    protected Object doExecute() throws Exception {
+        Configuration[] configs = configRepository.getConfigAdmin().listConfigurations(query);
+        if (configs != null) {
+            Map<String, Configuration> sortedConfigs = new TreeMap<String, Configuration>();
+            for (Configuration config : configs) {
+                sortedConfigs.put(config.getPid(), config);
+            }
+            for (String pid : sortedConfigs.keySet()) {
+                Configuration config = sortedConfigs.get(pid);
+                System.out.println("----------------------------------------------------------------");
+                System.out.println("Pid:            " + config.getPid());
+                if (config.getFactoryPid() != null) {
+                    System.out.println("FactoryPid:     " + config.getFactoryPid());
+                }
+                System.out.println("BundleLocation: " + config.getBundleLocation());
+                if (config.getProperties() != null) {
+                    System.out.println("Properties:");
+                    Dictionary props = config.getProperties();
+                    Map<String, Object> sortedProps = new TreeMap<String, Object>();
+                    for (Enumeration e = props.keys(); e.hasMoreElements();) {
+                        Object key = e.nextElement();
+                        sortedProps.put(key.toString(), props.get(key));
+                    }
+                    for (String key : sortedProps.keySet()) {
+                        System.out.println("   " + key + " = " + sortedProps.get(key));
+                    }
+                }
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/PropAppendCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/PropAppendCommand.java b/config/src/main/java/org/apache/karaf/config/command/PropAppendCommand.java
new file mode 100644
index 0000000..f021146
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/PropAppendCommand.java
@@ -0,0 +1,50 @@
+/*
+ * 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.config.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.config.command.completers.ConfigurationPropertyCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "config", name = "property-append", description = "Appends the given value to an existing property or creates the property with the specified name and value.")
+@Service
+public class PropAppendCommand extends ConfigPropertyCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The name of the property", required = true, multiValued = false)
+    @Completion(ConfigurationPropertyCompleter.class)
+    String prop;
+
+    @Argument(index = 1, name = "value", description = "The value to append to the property", required = true, multiValued = false)
+    String value;
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    @Override
+    public void propertyAction(Dictionary props) {
+        final Object currentValue = props.get(prop);
+        if (currentValue == null) {
+            props.put(prop, value);
+        } else if (currentValue instanceof String) {
+            props.put(prop, currentValue + value);
+        } else {
+            System.err.println("Append Failed: current value is not a String.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/PropDelCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/PropDelCommand.java b/config/src/main/java/org/apache/karaf/config/command/PropDelCommand.java
new file mode 100644
index 0000000..e416cf6
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/PropDelCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.config.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+
+@Command(scope = "config", name = "property-delete", description = "Deletes a property from the configuration being edited.")
+@Service
+public class PropDelCommand extends ConfigPropertyCommandSupport {
+
+    @Argument(index = 0, name = "property", description = "The name of the property to delete", required = true, multiValued = false)
+    String prop;
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public void propertyAction(Dictionary props) {
+        props.remove(prop);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/PropListCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/PropListCommand.java b/config/src/main/java/org/apache/karaf/config/command/PropListCommand.java
new file mode 100644
index 0000000..a0d3a61
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/PropListCommand.java
@@ -0,0 +1,47 @@
+/*
+ * 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.config.command;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "config", name = "property-list", description = "Lists properties from the currently edited configuration.")
+@Service
+public class PropListCommand extends ConfigPropertyCommandSupport {
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public void propertyAction(Dictionary props) {
+        for (Enumeration e = props.keys(); e.hasMoreElements(); ) {
+            Object key = e.nextElement();
+            System.out.println("   " + key + " = " + props.get(key));
+        }
+    }
+
+    /**
+     * List commands never requires an update, so it always returns false.
+     * @param pid
+     * @return
+     */
+    @Override
+    protected boolean requiresUpdate(String pid) {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/PropSetCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/PropSetCommand.java b/config/src/main/java/org/apache/karaf/config/command/PropSetCommand.java
new file mode 100644
index 0000000..8337f6a
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/PropSetCommand.java
@@ -0,0 +1,43 @@
+/*
+ * 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.config.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.config.command.completers.ConfigurationPropertyCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "config", name = "property-set", description = "Sets a property in the currently edited configuration.")
+@Service
+public class PropSetCommand extends ConfigPropertyCommandSupport {
+
+    @Argument(index = 0, name = "property", description = "The name of the property to set", required = true, multiValued = false)
+    @Completion(ConfigurationPropertyCompleter.class)
+    String prop;
+
+    @Argument(index = 1, name = "value", description = "The value of the property", required = true, multiValued = false)
+    String value;
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    @Override
+    public void propertyAction(Dictionary props) {
+        props.put(prop, value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/UpdateCommand.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/UpdateCommand.java b/config/src/main/java/org/apache/karaf/config/command/UpdateCommand.java
new file mode 100644
index 0000000..cc368b8
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/UpdateCommand.java
@@ -0,0 +1,48 @@
+/*
+ * 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.config.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "config", name = "update", description = "Saves and propagates changes from the configuration being edited.")
+@Service
+public class UpdateCommand extends ConfigCommandSupport {
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected Object doExecute() throws Exception {
+        Dictionary props = getEditedProps();
+        if (props == null) {
+            System.err.println("No configuration is being edited--run the edit command first");
+            return null;
+        }
+
+        String pid = (String) this.session.get(PROPERTY_CONFIG_PID);
+        boolean isFactory = this.session.get(PROPERTY_FACTORY) != null && (Boolean) this.session.get(PROPERTY_FACTORY);
+        if (isFactory) {
+        	this.configRepository.createFactoryConfiguration(pid, props);
+        } else {
+        	this.configRepository.update(pid, props);
+        }
+        this.session.put(PROPERTY_CONFIG_PID, null);
+        this.session.put(PROPERTY_FACTORY, null);
+        this.session.put(PROPERTY_CONFIG_PROPS, null);
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationCompleter.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationCompleter.java b/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationCompleter.java
new file mode 100644
index 0000000..fe60c56
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationCompleter.java
@@ -0,0 +1,103 @@
+/*
+ * 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.config.command.completers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.karaf.shell.api.action.lifecycle.Destroy;
+import org.apache.karaf.shell.api.action.lifecycle.Init;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+
+/**
+ * {@link Completer} for Configuration Admin configurations.
+ *
+ * Displays a list of existing config instance configurations for completion.
+ *
+ */
+@Service
+public class ConfigurationCompleter implements Completer, ConfigurationListener {
+
+    private final StringsCompleter delegate = new StringsCompleter();
+
+    @Reference
+    private ConfigurationAdmin admin;
+
+    @Reference
+    private BundleContext bundleContext;
+
+    private ServiceRegistration<ConfigurationListener> registration;
+
+    public void setAdmin(ConfigurationAdmin admin) {
+        this.admin = admin;
+    }
+
+    @Init
+    public void init() {
+        registration = bundleContext.registerService(ConfigurationListener.class, this, null);
+
+        Configuration[] configs;
+        try {
+            configs = admin.listConfigurations(null);
+            if (configs == null) {
+                return;
+            }
+        } catch (Exception e) {
+            return;
+        }
+
+        Collection<String> pids = new ArrayList<String>();
+        for (Configuration config : configs) {
+            pids.add(config.getPid());
+        }
+
+        delegate.getStrings().addAll(pids);
+    }
+
+    @Destroy
+    public void destroy() {
+        registration.unregister();
+    }
+
+    public int complete(final Session session, final CommandLine commandLine, final List<String> candidates) {
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+    public void configurationEvent(ConfigurationEvent configurationEvent) {
+        String pid = configurationEvent.getPid();
+        if (configurationEvent.getType() == ConfigurationEvent.CM_DELETED) {
+            delegate.getStrings().remove(pid);
+        } else if (configurationEvent.getType() == ConfigurationEvent.CM_UPDATED) {
+            delegate.getStrings().add(pid);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationPropertyCompleter.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationPropertyCompleter.java b/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationPropertyCompleter.java
new file mode 100644
index 0000000..2b43fec
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/command/completers/ConfigurationPropertyCompleter.java
@@ -0,0 +1,136 @@
+/*
+ * 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.config.command.completers;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.karaf.config.command.ConfigCommandSupport;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * {@link Completer} for Configuration Admin properties.
+ *
+ * Displays a list of existing properties based on the current configuration being edited.
+ *
+ */
+@Service
+public class ConfigurationPropertyCompleter implements Completer {
+
+    private final StringsCompleter delegate = new StringsCompleter();
+
+    private static final String OPTION = "-p";
+    private static final String ALIAS = "--pid";
+
+    @Reference
+    private ConfigurationAdmin configAdmin;
+
+    @SuppressWarnings("rawtypes")
+    public int complete(final Session session, final CommandLine commandLine, final List<String> candidates) {
+        if (session != null) {
+            String pid = getPid(session, commandLine);
+            Set<String> propertyNames = getPropertyNames(pid);
+            delegate.getStrings().clear();
+            if (propertyNames != null && !propertyNames.isEmpty()) {
+                delegate.getStrings().addAll(propertyNames);
+            }
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+    /**
+     * Retrieves the pid stored in the {@link Session} or passed as an argument.
+     * Argument takes precedence from pid stored in the {@link Session}.
+     */
+    private String getPid(Session session, CommandLine commandLine) {
+        String pid = (String) session.get(ConfigCommandSupport.PROPERTY_CONFIG_PID);
+        if (commandLine.getArguments().length > 0) {
+            List<String> arguments = Arrays.asList(commandLine.getArguments());
+            if (arguments.contains(OPTION)) {
+                int index = arguments.indexOf(OPTION);
+                if (arguments.size() > index) {
+                    return arguments.get(index + 1);
+                }
+            }
+
+            if (arguments.contains(ALIAS)) {
+                int index = arguments.indexOf(ALIAS);
+                if (arguments.size() > index) {
+                    return arguments.get(index + 1);
+                }
+            }
+        }
+        return pid;
+    }
+
+    /**
+     * Returns the property names for the given pid.
+     * @param pid
+     * @return
+     */
+    @SuppressWarnings("rawtypes")
+    private Set<String> getPropertyNames(String pid) {
+        Set<String> propertyNames = new HashSet<String>();
+        if (pid != null) {
+            Configuration configuration = null;
+            try {
+                Configuration[] configs = configAdmin.listConfigurations("(service.pid="+pid+")");
+                if (configs != null && configs.length > 0) {
+                    configuration = configs[0];
+                    if (configuration != null) {
+                        Dictionary properties = configuration.getProperties();
+                        if (properties != null) {
+                            Enumeration keys = properties.keys();
+                            while (keys.hasMoreElements()) {
+                                propertyNames.add(String.valueOf(keys.nextElement()));
+                            }
+                        }
+                    }
+                }
+            } catch (IOException e) {
+              //Ignore
+            } catch (InvalidSyntaxException e) {
+                //Ignore
+            }
+        }
+        return propertyNames;
+    }
+
+    public ConfigurationAdmin getConfigAdmin() {
+        return configAdmin;
+    }
+
+    public void setConfigAdmin(ConfigurationAdmin configAdmin) {
+        this.configAdmin = configAdmin;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/core/ConfigMBean.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/core/ConfigMBean.java b/config/src/main/java/org/apache/karaf/config/core/ConfigMBean.java
new file mode 100644
index 0000000..9cb9f7f
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/core/ConfigMBean.java
@@ -0,0 +1,107 @@
+/*
+ * 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.config.core;
+
+import javax.management.MBeanException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * MBean to manipulate the Config layer.
+ */
+public interface ConfigMBean {
+
+    /**
+     * Get the list of all configuration PIDs.
+     *
+     * @return the list of all configuration PIDs.
+     * @throws Exception
+     */
+    List<String> getConfigs() throws MBeanException;
+
+    /**
+     * Create a new configuration for the given PID.
+     *
+     * @param pid the configuration PID.
+     * @throws Exception
+     */
+    void create(String pid) throws MBeanException;
+
+    /**
+     * Delete a configuration identified by the given PID.
+     *
+     * @param pid the configuration PID to delete.
+     * @throws Exception
+     */
+    void delete(String pid) throws MBeanException;
+
+    /**
+     * Get the list of properties for a configuration PID.
+     *
+     * @param pid the configuration PID.
+     * @return the list of properties.
+     * @throws Exception
+     */
+    Map<String, String> listProperties(String pid) throws MBeanException;
+
+    /**
+     * Remove the configuration property identified by the given key.
+     *
+     * @param pid the configuration PID.
+     * @param key the property key.
+     * @throws Exception
+     */
+    void deleteProperty(String pid, String key) throws MBeanException;
+
+    /**
+     * Append (or add) a value for the given configuration key.
+     *
+     * @param pid the configuration PID.
+     * @param key the property key.
+     * @param value the value to append to the current property value.
+     * @throws Exception
+     */
+    void appendProperty(String pid, String key, String value) throws MBeanException;
+
+    /**
+     * Set a configuration property.
+     *
+     * @param pid the configuration PID.
+     * @param key the property key.
+     * @param value the property value.
+     * @throws Exception
+     */
+    void setProperty(String pid, String key, String value) throws MBeanException;
+
+    /**
+     * Update a complete configuration.
+     *
+     * @param pid the configuration PID.
+     * @param properties the new properties to set in the configuration.
+     * @throws MBeanException
+     */
+    void update(String pid, Map<String, String> properties) throws MBeanException;
+    
+    /**
+     * Create a factory based configuration.
+     *
+     * @param factoryPid
+     * @param properties the new properties to set in the configuration.
+     * @return created pid
+     * @throws MBeanException
+     */
+    String createFactoryConfiguration(String factoryPid, Map<String, String> properties) throws MBeanException;
+
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/core/ConfigRepository.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/core/ConfigRepository.java b/config/src/main/java/org/apache/karaf/config/core/ConfigRepository.java
new file mode 100644
index 0000000..8121679
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/core/ConfigRepository.java
@@ -0,0 +1,51 @@
+/*
+ * 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.config.core;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public interface ConfigRepository {
+
+    /**
+     * Saves config to storage or ConfigurationAdmin.
+     * @param pid
+     * @param props
+     * @throws IOException
+     */
+    @SuppressWarnings("rawtypes")
+    void update(String pid, Dictionary props) throws IOException;
+
+    void delete(String pid) throws Exception;
+
+    @SuppressWarnings("rawtypes")
+    Dictionary getConfigProperties(String pid) throws IOException, InvalidSyntaxException;
+
+    ConfigurationAdmin getConfigAdmin();
+
+    /**
+     * Create a factory based configuration.
+     *
+     * @param factoryPid
+     * @param properties the new properties to set in the configuration.
+     * @return created pid
+     */
+	String createFactoryConfiguration(String factoryPid, Dictionary<String, ?> properties);
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/core/impl/ConfigMBeanImpl.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/core/impl/ConfigMBeanImpl.java b/config/src/main/java/org/apache/karaf/config/core/impl/ConfigMBeanImpl.java
new file mode 100644
index 0000000..a8b8090
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/core/impl/ConfigMBeanImpl.java
@@ -0,0 +1,186 @@
+/*
+ * 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.config.core.impl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.StandardMBean;
+
+import org.apache.karaf.config.core.ConfigMBean;
+import org.apache.karaf.config.core.ConfigRepository;
+import org.osgi.service.cm.Configuration;
+
+/**
+ * Implementation of the ConfigMBean.
+ */
+public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean {
+
+    private ConfigRepository configRepo;
+
+    public ConfigMBeanImpl() throws NotCompliantMBeanException {
+        super(ConfigMBean.class);
+    }
+
+    private Configuration getConfiguration(String pid) throws IOException {
+        Configuration configuration = configRepo.getConfigAdmin().getConfiguration(pid);
+        if (configuration == null) {
+            throw new IllegalArgumentException("Configuration PID " + pid + " doesn't exist");
+        }
+        return configuration;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private Dictionary getConfigProperties(String pid) throws IOException {
+        Configuration configuration = getConfiguration(pid);
+
+        Dictionary dictionary = configuration.getProperties();
+        if (dictionary == null) {
+            dictionary = new java.util.Properties();
+        }
+        return dictionary;
+    }
+
+    /**
+     * Get all config pids
+     */
+    public List<String> getConfigs() throws MBeanException {
+        try {
+            Configuration[] configurations = this.configRepo.getConfigAdmin().listConfigurations(null);
+            List<String> pids = new ArrayList<String>();
+            for (int i = 0; i < configurations.length; i++) {
+                pids.add(configurations[i].getPid());
+            }
+            return pids;
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    public void create(String pid) throws MBeanException {
+        try {
+            configRepo.update(pid, new Hashtable());
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    public void delete(String pid) throws MBeanException {
+        try {
+            this.configRepo.delete(pid);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    public Map<String, String> listProperties(String pid) throws MBeanException {
+        try {
+            Dictionary dictionary = getConfigProperties(pid);
+
+            Map<String, String> propertiesMap = new HashMap<String, String>();
+            for (Enumeration e = dictionary.keys(); e.hasMoreElements(); ) {
+                Object key = e.nextElement();
+                Object value = dictionary.get(key);
+                propertiesMap.put(key.toString(), value.toString());
+            }
+            return propertiesMap;
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    public void deleteProperty(String pid, String key) throws MBeanException {
+        try {
+            Dictionary dictionary = getConfigProperties(pid);
+            dictionary.remove(key);
+            configRepo.update(pid, dictionary);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void appendProperty(String pid, String key, String value) throws MBeanException {
+        try {
+            Dictionary dictionary = getConfigProperties(pid);
+            Object currentValue = dictionary.get(key);
+            if (currentValue == null) {
+                dictionary.put(key, value);
+            } else if (currentValue instanceof String) {
+                dictionary.put(key, currentValue + value);
+            } else {
+                throw new IllegalStateException("Current value is not a String");
+            }
+            configRepo.update(pid, dictionary);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void setProperty(String pid, String key, String value) throws MBeanException {
+        try {
+            Dictionary dictionary = getConfigProperties(pid);
+            dictionary.put(key, value);
+            configRepo.update(pid, dictionary);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    public void update(String pid, Map<String, String> properties) throws MBeanException {
+        try {
+            if (properties == null) {
+                properties = new HashMap<String, String>();
+            }
+            Dictionary<String, String> dictionary = toDictionary(properties);
+            configRepo.update(pid, dictionary);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+	private Dictionary<String, String> toDictionary(
+			Map<String, String> properties) {
+		Dictionary<String, String> dictionary = new Hashtable<String, String>();
+		for (String key : properties.keySet()) {
+		    dictionary.put(key, properties.get(key));
+		}
+		return dictionary;
+	}
+
+
+    public void setConfigRepo(ConfigRepository configRepo) {
+        this.configRepo = configRepo;
+    }
+
+	@Override
+	public String createFactoryConfiguration(String factoryPid,
+			Map<String, String> properties) throws MBeanException {
+		Dictionary<String, String> dict = toDictionary(properties);
+		return configRepo.createFactoryConfiguration(factoryPid, dict);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/core/impl/ConfigRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/core/impl/ConfigRepositoryImpl.java b/config/src/main/java/org/apache/karaf/config/core/impl/ConfigRepositoryImpl.java
new file mode 100644
index 0000000..11bb720
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/core/impl/ConfigRepositoryImpl.java
@@ -0,0 +1,99 @@
+/*
+ * 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.config.core.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.karaf.config.core.ConfigRepository;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class ConfigRepositoryImpl implements ConfigRepository {
+    private ConfigurationAdmin configAdmin;
+    
+    private File storage;
+
+    public ConfigRepositoryImpl(ConfigurationAdmin configAdmin) {
+        this.configAdmin = configAdmin;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.karaf.shell.config.impl.ConfigRepository#update(java.lang.String, java.util.Dictionary, boolean)
+     */
+    @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public void update(String pid, Dictionary props) throws IOException {
+        Configuration cfg = this.configAdmin.getConfiguration(pid, null);
+        if (cfg.getBundleLocation() != null) {
+            cfg.setBundleLocation(null);
+        }
+        cfg.update(props);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.karaf.shell.config.impl.ConfigRepository#delete(java.lang.String)
+     */
+    @Override
+    public void delete(String pid) throws Exception {
+        Configuration configuration = this.configAdmin.getConfiguration(pid);
+        configuration.delete();
+        deleteStorage(pid);
+    }
+    
+    protected void deleteStorage(String pid) throws Exception {
+        if (storage != null) {
+            File cfgFile = new File(storage, pid + ".cfg");
+            cfgFile.delete();
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.karaf.shell.config.impl.ConfigRepository#getConfigProperties(java.lang.String)
+     */
+    @Override
+    @SuppressWarnings("rawtypes")
+    public Dictionary getConfigProperties(String pid) throws IOException, InvalidSyntaxException {
+        if(pid != null && configAdmin != null) {
+            Configuration configuration = this.configAdmin.getConfiguration(pid);
+            if(configuration != null) {
+                Dictionary props = configuration.getProperties();
+                return (props != null) ? props : new Hashtable<String, String>();
+            }
+        }
+        return null;
+    }
+
+    public ConfigurationAdmin getConfigAdmin() {
+        return this.configAdmin;
+    }
+
+	@Override
+	public String createFactoryConfiguration(String factoryPid, Dictionary<String, ?> properties) {
+		try {
+			Configuration config = configAdmin.createFactoryConfiguration(factoryPid);
+			config.update(properties);
+			return config.getPid();
+		} catch (IOException e) {
+			throw new RuntimeException(e.getMessage(), e);
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/java/org/apache/karaf/config/core/impl/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/config/core/impl/osgi/Activator.java b/config/src/main/java/org/apache/karaf/config/core/impl/osgi/Activator.java
new file mode 100644
index 0000000..bdfab09
--- /dev/null
+++ b/config/src/main/java/org/apache/karaf/config/core/impl/osgi/Activator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.config.core.impl.osgi;
+
+import org.apache.karaf.config.core.ConfigRepository;
+import org.apache.karaf.config.core.impl.ConfigMBeanImpl;
+import org.apache.karaf.config.core.impl.ConfigRepositoryImpl;
+import org.apache.karaf.util.tracker.BaseActivator;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class Activator extends BaseActivator {
+
+    @Override
+    protected void doOpen() throws Exception {
+        trackService(ConfigurationAdmin.class);
+    }
+
+    protected void doStart() throws Exception {
+        ConfigurationAdmin configurationAdmin = getTrackedService(ConfigurationAdmin.class);
+        if (configurationAdmin == null) {
+            return;
+        }
+
+        ConfigRepository configRepository = new ConfigRepositoryImpl(configurationAdmin);
+        register(ConfigRepository.class, configRepository);
+
+        ConfigMBeanImpl configMBean = new ConfigMBeanImpl();
+        configMBean.setConfigRepo(configRepository);
+        registerMBean(configMBean, "type=config");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/config/src/main/resources/OSGI-INF/bundle.info b/config/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..3cd35da
--- /dev/null
+++ b/config/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,27 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+This bundle provides Karaf shell commands to manipulate the ConfigAdmin OSGi service.
+
+The following commands are available:
+* config:cancel - Cancels the changes to the configuration being edited.
+* config:edit - Creates or edits a configuration.
+* config:list - Lists existing configurations.
+* config:propappend - Appends the given value to an existing property or creates
+ the property with the specified name and value.
+* config:propdel - Deletes a property from the edited configuration.
+* config:proplist - Lists properties from the currently edited configuration.
+* config:propset - Sets a property in the currently edited configuration.
+* config:update - Saves and propagates changes from the configuration being edited.
+
+h1. See also
+
+Commands - section of the Karaf User Guide.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/resources/OSGI-INF/metatype/metatype.properties
----------------------------------------------------------------------
diff --git a/config/src/main/resources/OSGI-INF/metatype/metatype.properties b/config/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..3bce187
--- /dev/null
+++ b/config/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,28 @@
+#
+#  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.
+#
+
+#
+# This file contains localization strings for configuration labels and
+# descriptions as used in the metatype.xml descriptor
+
+config.name = Apache Karaf Shell Config
+config.description = Configuration of Apache Karaf Shell Config
+
+storage.name = Storage directory
+storage.description = the directory used as a storage for configurations

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/resources/OSGI-INF/metatype/metatype.xml
----------------------------------------------------------------------
diff --git a/config/src/main/resources/OSGI-INF/metatype/metatype.xml b/config/src/main/resources/OSGI-INF/metatype/metatype.xml
new file mode 100644
index 0000000..83d3242
--- /dev/null
+++ b/config/src/main/resources/OSGI-INF/metatype/metatype.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0" localization="OSGI-INF/metatype/metatype">
+    <OCD id="org.apache.karaf.config" name="%config.name" description="%config.description">
+        <AD id="storage" type="String" default="${karaf.etc}/"
+            name="%storage.name" description="%storage.description"/>
+    </OCD>
+    <Designate pid="org.apache.karaf.config">
+        <Object ocdref="org.apache.karaf.config"/>
+    </Designate>
+</metatype:MetaData>

http://git-wip-us.apache.org/repos/asf/karaf/blob/d33e0955/config/src/main/resources/org/apache/karaf/config/command/edit.txt
----------------------------------------------------------------------
diff --git a/config/src/main/resources/org/apache/karaf/config/command/edit.txt b/config/src/main/resources/org/apache/karaf/config/command/edit.txt
new file mode 100644
index 0000000..88fa6d5
--- /dev/null
+++ b/config/src/main/resources/org/apache/karaf/config/command/edit.txt
@@ -0,0 +1,13 @@
+The edit command can be used to create or edit a configuration in three ways.
+
+Edit or create a config by pid:
+  > config:edit org.apache.karaf.sample.pid
+The command above will also create a file etc/org.apache.karaf.sample.pid which corresponds to a configuration object with pid org.apache.karaf.sample.pid.
+  
+Create a factory config by factory pid:
+  > config:edit --factory myfactorypid
+In this case the config is created with a pid like myfactorypid.<generated id>. This config is not written to a file.
+
+Edit a config specified by an ldap query
+  > config:edit '(myattribute=myvalue)'
+This executes an ldap query like in config:list. If the result is exactly one config then it is edited.