You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by cs...@apache.org on 2014/01/13 17:07:22 UTC

git commit: KARAF-2676 Allow creation and updates to managed service factory configs

Updated Branches:
  refs/heads/master b00b8934e -> 7565c4a72


KARAF-2676 Allow creation and updates to managed service factory configs


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

Branch: refs/heads/master
Commit: 7565c4a7243ddf2623e5554864552606ee56aedf
Parents: b00b893
Author: Christian Schneider <ch...@die-schneider.net>
Authored: Mon Jan 13 17:06:15 2014 +0100
Committer: Christian Schneider <ch...@die-schneider.net>
Committed: Mon Jan 13 17:06:15 2014 +0100

----------------------------------------------------------------------
 .../config/command/ConfigCommandSupport.java    |  1 +
 .../karaf/config/command/EditCommand.java       | 19 +++-
 .../karaf/config/command/UpdateCommand.java     | 10 ++-
 .../org/apache/karaf/config/command/edit.txt    | 22 ++---
 .../karaf/config/command/UpdateCommandTest.java | 80 +++++++++--------
 .../apache/karaf/config/core/ConfigMBean.java   | 12 ++-
 .../karaf/config/core/ConfigRepository.java     |  9 ++
 .../karaf/config/core/impl/ConfigMBeanImpl.java | 21 ++++-
 .../config/core/impl/ConfigRepositoryImpl.java  | 36 +++-----
 .../itests/ConfigManagedServiceFactoryTest.java | 94 ++++++++++++++------
 .../src/test/resources/etc/myconfig-test1.cfg   |  2 +
 11 files changed, 195 insertions(+), 111 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/7565c4a7/config/command/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java
----------------------------------------------------------------------
diff --git a/config/command/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java b/config/command/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java
index 08f8715..bfd0c12 100644
--- a/config/command/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java
+++ b/config/command/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java
@@ -30,6 +30,7 @@ import org.apache.karaf.shell.console.OsgiCommandSupport;
 public abstract class ConfigCommandSupport extends OsgiCommandSupport {
     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";
     protected ConfigRepository configRepository;
 
     @SuppressWarnings("rawtypes")

http://git-wip-us.apache.org/repos/asf/karaf/blob/7565c4a7/config/command/src/main/java/org/apache/karaf/config/command/EditCommand.java
----------------------------------------------------------------------
diff --git a/config/command/src/main/java/org/apache/karaf/config/command/EditCommand.java b/config/command/src/main/java/org/apache/karaf/config/command/EditCommand.java
index 1c84221..60ba76e 100644
--- a/config/command/src/main/java/org/apache/karaf/config/command/EditCommand.java
+++ b/config/command/src/main/java/org/apache/karaf/config/command/EditCommand.java
@@ -21,15 +21,19 @@ import java.util.Dictionary;
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
+import org.osgi.service.cm.Configuration;
 
 @Command(scope = "config", name = "edit", description = "Creates or edits a configuration.", detailedDescription="classpath:edit.txt")
 public class EditCommand extends ConfigCommandSupport {
 
-    @Argument(index = 0, name = "pid", description = "PID of the configuration", required = true, multiValued = false)
+    @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)
     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 {
@@ -38,9 +42,22 @@ public class EditCommand extends ConfigCommandSupport {
             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/7565c4a7/config/command/src/main/java/org/apache/karaf/config/command/UpdateCommand.java
----------------------------------------------------------------------
diff --git a/config/command/src/main/java/org/apache/karaf/config/command/UpdateCommand.java b/config/command/src/main/java/org/apache/karaf/config/command/UpdateCommand.java
index 5ee41d2..2c5a547 100644
--- a/config/command/src/main/java/org/apache/karaf/config/command/UpdateCommand.java
+++ b/config/command/src/main/java/org/apache/karaf/config/command/UpdateCommand.java
@@ -23,7 +23,7 @@ import org.apache.karaf.shell.commands.Command;
 @Command(scope = "config", name = "update", description = "Saves and propagates changes from the configuration being edited.")
 public class UpdateCommand extends ConfigCommandSupport {
 
-    @SuppressWarnings("rawtypes")
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     protected Object doExecute() throws Exception {
         Dictionary props = getEditedProps();
         if (props == null) {
@@ -32,8 +32,14 @@ public class UpdateCommand extends ConfigCommandSupport {
         }
 
         String pid = (String) this.session.get(PROPERTY_CONFIG_PID);
-        this.configRepository.update(pid, props);
+        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/7565c4a7/config/command/src/main/resources/org/apache/karaf/config/command/edit.txt
----------------------------------------------------------------------
diff --git a/config/command/src/main/resources/org/apache/karaf/config/command/edit.txt b/config/command/src/main/resources/org/apache/karaf/config/command/edit.txt
index aa68062..88fa6d5 100644
--- a/config/command/src/main/resources/org/apache/karaf/config/command/edit.txt
+++ b/config/command/src/main/resources/org/apache/karaf/config/command/edit.txt
@@ -1,13 +1,13 @@
-The edit command can be used to create or edit a configuration by passing its pid as argument.
-  > config:edit org.apache.karaf.sample.pid
-The command above will create a file etc/org.apache.karaf.sample.pid which corresponds to a configuration object with pid org.apache.karaf.sample.pid
-
-In case of Managed Service Factories the user can create or edit the configuration of a specific instance of a managed service.
-  > config:edit org.apache.karaf.sample.service.factory.pid-instanceid
-The command above will create a file etc/org.apache.karaf.sample.service.factory.pid-instanceid but in this case the pid is generated, according to the specification.
+The edit command can be used to create or edit a configuration in three ways.
 
-This makes further editing to the configuration difficult because the generated pid is not known to the user. To make things simple config:edit provides a special flag -f or --use-file which allows editing a configuration using the filename instead of the pid.
-So the user can simply edit again the configuration by typing:
-  > config:edit org.apache.karaf.sample.service.factory.pid-instanceid.
+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.
 
-The --factory option can be used to create a new configuration for a given factory pid.  The parameter will be used as the factory pid and the configuration pid will be generated.  Note that this option
\ No newline at end of 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.

http://git-wip-us.apache.org/repos/asf/karaf/blob/7565c4a7/config/command/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java
----------------------------------------------------------------------
diff --git a/config/command/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java b/config/command/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java
index 2d2eece..64d92ac 100644
--- a/config/command/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java
+++ b/config/command/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java
@@ -17,71 +17,73 @@
 package org.apache.karaf.config.command;
 
 
-import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 
 import java.util.Dictionary;
-import java.util.Properties;
+import java.util.Hashtable;
 
 import junit.framework.TestCase;
 
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.config.core.impl.ConfigRepositoryImpl;
+import org.apache.karaf.config.core.ConfigRepository;
 import org.easymock.EasyMock;
 import org.osgi.framework.BundleContext;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
 
 /**
  * Test cases for {@link EditCommand}
  */
 public class UpdateCommandTest extends TestCase {
 
-    private static final String PID = "my.test.persistent.id-other";
+    private static final String FACTORY_PID = "myFactoryPid";
+    private static final String PID = "myPid";
 
-    private UpdateCommand command;
-    private BundleContext context;
-    private ConfigurationAdmin admin;
-    private CommandSession session;
+    public void testupdateRegularConfig() throws Exception {
+		Dictionary<String, Object> props = new Hashtable<String, Object>();
 
-    @Override
-    protected void setUp() throws Exception {
-        command = new UpdateCommand();
-
-        context = EasyMock.createMock(BundleContext.class);
+        UpdateCommand command = new UpdateCommand();
+        BundleContext context = EasyMock.createMock(BundleContext.class);
         command.setBundleContext(context);
-
-        admin = createMock(ConfigurationAdmin.class);
-        command.setConfigRepository(new ConfigRepositoryImpl(admin));
+        ConfigRepository configRepo = EasyMock.createMock(ConfigRepository.class);
+        configRepo.update(EasyMock.eq(PID), EasyMock.eq(props));
+        EasyMock.expectLastCall();
+		command.setConfigRepository(configRepo);
         expect(context.getBundle(0)).andReturn(null).anyTimes();
-
+        
+        MockCommandSession session = createMockSessionForFactoryEdit(PID, false, props);
         replay(context);
+        replay(configRepo);
 
-        session = new MockCommandSession();
+        command.execute(session);
+        EasyMock.verify(context, configRepo);
     }
-
+    
     public void testupdateOnNewFactoryPid() throws Exception {
-        Dictionary props = new Properties();
-
-        session.put(ConfigCommandSupport.PROPERTY_CONFIG_PID, PID);
-        session.put(ConfigCommandSupport.PROPERTY_CONFIG_PROPS, props);
-
-        Configuration configNew = createMock(Configuration.class);
-        expect(admin.getConfiguration(PID, null)).andReturn(configNew);
-        expect(configNew.getProperties()).andReturn(null);
+		Dictionary<String, Object> props = new Hashtable<String, Object>();
 
-
-        Configuration configFac = createMock(Configuration.class);
-        expect(admin.createFactoryConfiguration(PID.substring(0, PID.indexOf('-')), null)).andReturn(configFac);
-        configFac.update(props);
-        expect(configFac.getBundleLocation()).andReturn(null);
-        replay(admin);
-        replay(configNew);
-        replay(configFac);
+        UpdateCommand command = new UpdateCommand();
+        BundleContext context = EasyMock.createMock(BundleContext.class);
+        command.setBundleContext(context);
+        ConfigRepository configRepo = EasyMock.createMock(ConfigRepository.class);
+        expect(configRepo.createFactoryConfiguration(EasyMock.eq(FACTORY_PID), EasyMock.eq(props)))
+        	.andReturn(PID + ".35326647");
+		command.setConfigRepository(configRepo);
+        expect(context.getBundle(0)).andReturn(null).anyTimes();
+        
+        MockCommandSession session = createMockSessionForFactoryEdit(FACTORY_PID, true, props);
+        replay(context);
+        replay(configRepo);
 
         command.execute(session);
-
+        EasyMock.verify(context, configRepo);
     }
 
+	private MockCommandSession createMockSessionForFactoryEdit(String pid, boolean isFactory, 
+			Dictionary<String, Object> props) {
+		MockCommandSession session = new MockCommandSession();
+        session.put(ConfigCommandSupport.PROPERTY_CONFIG_PID, pid);
+        session.put(ConfigCommandSupport.PROPERTY_FACTORY, isFactory);
+        session.put(ConfigCommandSupport.PROPERTY_CONFIG_PROPS, props);
+		return session;
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/7565c4a7/config/core/src/main/java/org/apache/karaf/config/core/ConfigMBean.java
----------------------------------------------------------------------
diff --git a/config/core/src/main/java/org/apache/karaf/config/core/ConfigMBean.java b/config/core/src/main/java/org/apache/karaf/config/core/ConfigMBean.java
index 229645b..9cb9f7f 100644
--- a/config/core/src/main/java/org/apache/karaf/config/core/ConfigMBean.java
+++ b/config/core/src/main/java/org/apache/karaf/config/core/ConfigMBean.java
@@ -14,7 +14,6 @@
 package org.apache.karaf.config.core;
 
 import javax.management.MBeanException;
-import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
@@ -93,5 +92,16 @@ public interface ConfigMBean {
      * @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/7565c4a7/config/core/src/main/java/org/apache/karaf/config/core/ConfigRepository.java
----------------------------------------------------------------------
diff --git a/config/core/src/main/java/org/apache/karaf/config/core/ConfigRepository.java b/config/core/src/main/java/org/apache/karaf/config/core/ConfigRepository.java
index 54be7ec..8121679 100644
--- a/config/core/src/main/java/org/apache/karaf/config/core/ConfigRepository.java
+++ b/config/core/src/main/java/org/apache/karaf/config/core/ConfigRepository.java
@@ -39,4 +39,13 @@ public interface ConfigRepository {
     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/7565c4a7/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
index 6133ea2..a8b8090 100644
--- 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
@@ -155,19 +155,32 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean {
             if (properties == null) {
                 properties = new HashMap<String, String>();
             }
-            Dictionary<String, String> dictionary = new Hashtable<String, String>();
-            for (String key : properties.keySet()) {
-                dictionary.put(key, properties.get(key));
-            }
+            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/7565c4a7/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
index 1eeb71b..11bb720 100644
--- 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
@@ -39,38 +39,15 @@ public class ConfigRepositoryImpl implements ConfigRepository {
      * @see org.apache.karaf.shell.config.impl.ConfigRepository#update(java.lang.String, java.util.Dictionary, boolean)
      */
     @Override
-    @SuppressWarnings("rawtypes")
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     public void update(String pid, Dictionary props) throws IOException {
         Configuration cfg = this.configAdmin.getConfiguration(pid, null);
-        if (cfg.getProperties() == null) {
-            PidParts pidParts = parsePid(pid);
-            if (pidParts.factoryPid != null) {
-                cfg = this.configAdmin.createFactoryConfiguration(pidParts.pid, null);
-            }
-        }
         if (cfg.getBundleLocation() != null) {
             cfg.setBundleLocation(null);
         }
         cfg.update(props);
     }
 
-    private PidParts parsePid(String sourcePid) {
-        PidParts pidParts = new PidParts();
-        int n = sourcePid.indexOf('-');
-        if (n > 0) {
-            pidParts.factoryPid = sourcePid.substring(n + 1);
-            pidParts.pid = sourcePid.substring(0, n);
-        } else {
-            pidParts.pid = sourcePid;
-        }
-        return pidParts;
-    }
-    
-    private class PidParts {
-        String pid;
-        String factoryPid;
-    }
-    
     /* (non-Javadoc)
      * @see org.apache.karaf.shell.config.impl.ConfigRepository#delete(java.lang.String)
      */
@@ -108,4 +85,15 @@ public class ConfigRepositoryImpl implements ConfigRepository {
         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/7565c4a7/itests/src/test/java/org/apache/karaf/itests/ConfigManagedServiceFactoryTest.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/ConfigManagedServiceFactoryTest.java b/itests/src/test/java/org/apache/karaf/itests/ConfigManagedServiceFactoryTest.java
index 6966334..afeeaa2 100644
--- a/itests/src/test/java/org/apache/karaf/itests/ConfigManagedServiceFactoryTest.java
+++ b/itests/src/test/java/org/apache/karaf/itests/ConfigManagedServiceFactoryTest.java
@@ -17,6 +17,7 @@
 package org.apache.karaf.itests;
 
 import static org.junit.Assert.assertEquals;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.replaceConfigurationFile;
 
 import java.io.IOException;
 
@@ -25,6 +26,8 @@ import javax.inject.Inject;
 import org.apache.karaf.jaas.boot.principal.RolePrincipal;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
 import org.ops4j.pax.exam.spi.reactors.PerClass;
@@ -34,36 +37,69 @@ import org.osgi.service.cm.ConfigurationAdmin;
 
 @RunWith(PaxExam.class)
 @ExamReactorStrategy(PerClass.class)
-public class ConfigManagedServiceFactoryTest extends KarafTestSupport {  
-    
-    @Inject
-    ConfigurationAdmin configAdmin;
-    
-    @Test
-    public void updateProperties() throws IOException, InvalidSyntaxException {
-        executeCommand("config:edit myconfig-itest \n" +
-                       "config:property-set test1 test \n" +
-                       "config:property-set test2 test \n" +
-                       "config:update", new RolePrincipal("manager"));
-        Configuration config = readConfig();
-        assertThatPropertiesAreCorrect(config);
-        
-        executeCommand("config:edit myconfig-itest \n" +
-            "config:property-set test1 test \n" +
-            "config:update", new RolePrincipal("manager"));
-        config = readConfig();
-        // fails at property test2. See KARAF-2676
-        assertThatPropertiesAreCorrect(config);
-    }
+public class ConfigManagedServiceFactoryTest extends KarafTestSupport {
 
-    private void assertThatPropertiesAreCorrect(Configuration config) {
-        assertEquals("test", config.getProperties().get("test1"));
-        assertEquals("test", config.getProperties().get("test2"));
-    }
+	@Inject
+	ConfigurationAdmin configAdmin;
 
-    private Configuration readConfig() throws IOException, InvalidSyntaxException {
-        Configuration[]configs = configAdmin.listConfigurations("(service.factorypid=myconfig)");
-        return configs[0];
-    }
+	@org.ops4j.pax.exam.Configuration
+	public Option[] config() {
+		return new Option[] {
+				CoreOptions.composite(super.config()),
+				replaceConfigurationFile("etc/myconfig-test1.cfg",
+						getConfigFile("/etc/myconfig-test1.cfg")),
+		// KarafDistributionOption.debugConfiguration()
+		};
+	}
+
+	@Test
+	public void updateProperties() throws IOException, InvalidSyntaxException {
+		checkInitialValuesFromFelixConfigAdmin();
+		checkEditByFactoryPid();
+		CheckEditByArbitraryAttribute();
+	}
+	
+	@Test
+	public void createNewFactoryConfig() throws Exception {
+		executeCommand("config:edit --factory myconfig2\n"
+				+ "config:property-set test1 data1\n"
+				+ "config:update", new RolePrincipal("manager"));
+		Configuration config = configAdmin.listConfigurations("(service.factorypid=myconfig2)")[0];
+		assertEquals("data1", config.getProperties().get("test1"));
+	}
+
+	private void checkInitialValuesFromFelixConfigAdmin() throws IOException,
+			InvalidSyntaxException {
+		Configuration config = readConfig();
+		assertEquals("data1", config.getProperties().get("test1"));
+		assertEquals("data2", config.getProperties().get("test2"));
+	}
+
+	private void checkEditByFactoryPid() throws IOException,
+			InvalidSyntaxException {
+		executeCommand("config:edit '(service.factorypid=myconfig)'\n"
+				+ "config:property-set test1 data1new\n" + "config:update",
+				new RolePrincipal("manager"));
+		Configuration config = readConfig();
+		assertEquals("data1new", config.getProperties().get("test1"));
+		assertEquals("data2", config.getProperties().get("test2"));
+	}
+
+	private void CheckEditByArbitraryAttribute() throws IOException,
+			InvalidSyntaxException {
+		executeCommand("config:edit '(test2=data2)'\n"
+				+ "config:property-set test1 data1new2\n" + "config:update",
+				new RolePrincipal("manager"));
+		Configuration config = readConfig();
+		assertEquals("data1new2", config.getProperties().get("test1"));
+		assertEquals("data2", config.getProperties().get("test2"));
+	}
+
+	private Configuration readConfig() throws IOException,
+			InvalidSyntaxException {
+		Configuration[] configs = configAdmin
+				.listConfigurations("(service.factorypid=myconfig)");
+		return configs[0];
+	}
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/7565c4a7/itests/src/test/resources/etc/myconfig-test1.cfg
----------------------------------------------------------------------
diff --git a/itests/src/test/resources/etc/myconfig-test1.cfg b/itests/src/test/resources/etc/myconfig-test1.cfg
new file mode 100644
index 0000000..8e65829
--- /dev/null
+++ b/itests/src/test/resources/etc/myconfig-test1.cfg
@@ -0,0 +1,2 @@
+test1=data1
+test2=data2