Repository: karaf Updated Branches: refs/heads/master d3e170bda -> 0e016eda6
[KARAF-4843] Updating factory configuration leads to new configuration instance Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/ddeef77c Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/ddeef77c Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/ddeef77c Branch: refs/heads/master Commit: ddeef77cad3df9965766dc661f85525d1b149461 Parents: d3e170b Author: Christoph Fiehe <christoph.fi...@materna.de> Authored: Thu Nov 24 09:18:08 2016 +0100 Committer: Guillaume Nodet <gno...@apache.org> Committed: Wed Nov 30 09:08:29 2016 +0100 ---------------------------------------------------------------------- .../config/command/ConfigCommandSupport.java | 1 + .../karaf/config/command/EditCommand.java | 11 ++ .../karaf/config/command/UpdateCommand.java | 7 +- .../karaf/config/core/ConfigRepository.java | 10 +- .../karaf/config/core/impl/ConfigMBeanImpl.java | 45 +++---- .../config/core/impl/ConfigRepositoryImpl.java | 118 +++++++++++++------ .../org/apache/karaf/config/command/edit.txt | 6 +- .../karaf/config/command/UpdateCommandTest.java | 10 +- 8 files changed, 137 insertions(+), 71 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/ddeef77c/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 index 485988a..d70d61f 100644 --- a/config/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java +++ b/config/src/main/java/org/apache/karaf/config/command/ConfigCommandSupport.java @@ -35,6 +35,7 @@ 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"; + public static final String PROPERTY_ALIAS = "ConfigCommand.Alias"; @Reference protected ConfigRepository configRepository; http://git-wip-us.apache.org/repos/asf/karaf/blob/ddeef77c/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 index 3fcd820..9a47dd5 100644 --- a/config/src/main/java/org/apache/karaf/config/command/EditCommand.java +++ b/config/src/main/java/org/apache/karaf/config/command/EditCommand.java @@ -40,6 +40,10 @@ public class EditCommand extends ConfigCommandSupport { @Option(name = "--factory", aliases = {}, description = "Define this config as a factory config. Will be crearted on calling update", required = false, multiValued = false) boolean factory; + @Option(name = "--alias", aliases = {}, description = "Specifies the alias used for this factory config.", required = false, multiValued = false) + String alias; + + @Override @SuppressWarnings("rawtypes") protected Object doExecute() throws Exception { String oldPid = (String) this.session.get(PROPERTY_CONFIG_PID); @@ -63,10 +67,17 @@ public class EditCommand extends ConfigCommandSupport { System.out.println("Editing config " + pid); } + if (!factory && alias != null) { + System.err.println("The --alias only works in case of a factory configuration. Add the --factory option."); + } + 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); + if (alias != null) { + this.session.put(PROPERTY_ALIAS, alias); + } return null; } http://git-wip-us.apache.org/repos/asf/karaf/blob/ddeef77c/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 index cc368b8..3e36694 100644 --- a/config/src/main/java/org/apache/karaf/config/command/UpdateCommand.java +++ b/config/src/main/java/org/apache/karaf/config/command/UpdateCommand.java @@ -25,6 +25,7 @@ import org.apache.karaf.shell.api.action.lifecycle.Service; @Service public class UpdateCommand extends ConfigCommandSupport { + @Override @SuppressWarnings({ "rawtypes", "unchecked" }) protected Object doExecute() throws Exception { Dictionary props = getEditedProps(); @@ -36,13 +37,17 @@ public class UpdateCommand extends ConfigCommandSupport { 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); + String alias = (String) this.session.get(PROPERTY_ALIAS); + this.configRepository.createFactoryConfiguration(pid, alias, 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); + if (this.session.get(PROPERTY_ALIAS) != null) { + this.session.put(PROPERTY_ALIAS, null); + } return null; } } http://git-wip-us.apache.org/repos/asf/karaf/blob/ddeef77c/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 index 75a877b..55cb1b0 100644 --- a/config/src/main/java/org/apache/karaf/config/core/ConfigRepository.java +++ b/config/src/main/java/org/apache/karaf/config/core/ConfigRepository.java @@ -31,13 +31,11 @@ public interface ConfigRepository { * @param props the dictionary used to update the configuration. * @throws IOException in case of update failure. */ - @SuppressWarnings("rawtypes") - void update(String pid, Dictionary props) throws IOException; + void update(String pid, Dictionary<String, Object> props) throws IOException; void delete(String pid) throws Exception; - @SuppressWarnings("rawtypes") - Dictionary getConfigProperties(String pid) throws IOException, InvalidSyntaxException; + Dictionary<String, Object> getConfigProperties(String pid) throws IOException, InvalidSyntaxException; ConfigurationAdmin getConfigAdmin(); @@ -48,5 +46,7 @@ public interface ConfigRepository { * @param properties the new properties to set in the configuration. * @return the created configuration PID. */ - String createFactoryConfiguration(String factoryPid, Dictionary<String, ?> properties); + String createFactoryConfiguration(String factoryPid, Dictionary<String, Object> properties); + + String createFactoryConfiguration(String factoryPid, String alias, Dictionary<String, Object> properties); } http://git-wip-us.apache.org/repos/asf/karaf/blob/ddeef77c/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 index 8f3a582..489834b 100644 --- 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 @@ -49,13 +49,13 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { return configuration; } - @SuppressWarnings("rawtypes") - private Dictionary getConfigProperties(String pid) throws IOException { + @SuppressWarnings({ "unchecked", "rawtypes" }) + private Dictionary<String, Object> getConfigProperties(String pid) throws IOException { Configuration configuration = getConfiguration(pid); - Dictionary dictionary = configuration.getProperties(); + Dictionary<String, Object> dictionary = configuration.getProperties(); if (dictionary == null) { - dictionary = new java.util.Properties(); + dictionary = new Hashtable(new java.util.Properties()); } return dictionary; } @@ -63,10 +63,11 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { /** * Get all config pids */ + @Override public List<String> getConfigs() throws MBeanException { try { Configuration[] configurations = this.configRepo.getConfigAdmin().listConfigurations(null); - List<String> pids = new ArrayList<String>(); + List<String> pids = new ArrayList<>(); for (int i = 0; i < configurations.length; i++) { pids.add(configurations[i].getPid()); } @@ -76,15 +77,16 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { } } - @SuppressWarnings("rawtypes") + @Override public void create(String pid) throws MBeanException { try { - configRepo.update(pid, new Hashtable()); + configRepo.update(pid, new Hashtable<>()); } catch (Exception e) { throw new MBeanException(null, e.toString()); } } + @Override public void delete(String pid) throws MBeanException { try { this.configRepo.delete(pid); @@ -93,12 +95,13 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { } } + @Override @SuppressWarnings("rawtypes") public Map<String, String> listProperties(String pid) throws MBeanException { try { Dictionary dictionary = getConfigProperties(pid); - Map<String, String> propertiesMap = new HashMap<String, String>(); + Map<String, String> propertiesMap = new HashMap<>(); for (Enumeration e = dictionary.keys(); e.hasMoreElements(); ) { Object key = e.nextElement(); Object value = dictionary.get(key); @@ -110,10 +113,10 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { } } - @SuppressWarnings("rawtypes") + @Override public void deleteProperty(String pid, String key) throws MBeanException { try { - Dictionary dictionary = getConfigProperties(pid); + Dictionary<String, Object> dictionary = getConfigProperties(pid); dictionary.remove(key); configRepo.update(pid, dictionary); } catch (Exception e) { @@ -121,10 +124,10 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { } } - @SuppressWarnings({"rawtypes", "unchecked"}) + @Override public void appendProperty(String pid, String key, String value) throws MBeanException { try { - Dictionary dictionary = getConfigProperties(pid); + Dictionary<String, Object> dictionary = getConfigProperties(pid); Object currentValue = dictionary.get(key); if (currentValue == null) { dictionary.put(key, value); @@ -139,10 +142,10 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { } } - @SuppressWarnings({"rawtypes", "unchecked"}) + @Override public void setProperty(String pid, String key, String value) throws MBeanException { try { - Dictionary dictionary = getConfigProperties(pid); + Dictionary<String, Object> dictionary = getConfigProperties(pid); dictionary.put(key, value); configRepo.update(pid, dictionary); } catch (Exception e) { @@ -150,9 +153,10 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { } } + @Override public String getProperty(String pid, String key) throws MBeanException { try { - Dictionary dictionary = getConfigProperties(pid); + Dictionary<String, Object> dictionary = getConfigProperties(pid); Object value = dictionary.get(key); if (value != null) { return value.toString(); @@ -163,21 +167,22 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { } } + @Override public void update(String pid, Map<String, String> properties) throws MBeanException { try { if (properties == null) { - properties = new HashMap<String, String>(); + properties = new HashMap<>(); } - Dictionary<String, String> dictionary = toDictionary(properties); + Dictionary<String, Object> dictionary = toDictionary(properties); configRepo.update(pid, dictionary); } catch (Exception e) { throw new MBeanException(null, e.toString()); } } - private Dictionary<String, String> toDictionary( + private Dictionary<String, Object> toDictionary( Map<String, String> properties) { - Dictionary<String, String> dictionary = new Hashtable<String, String>(); + Dictionary<String, Object> dictionary = new Hashtable<>(); for (String key : properties.keySet()) { dictionary.put(key, properties.get(key)); } @@ -192,7 +197,7 @@ public class ConfigMBeanImpl extends StandardMBean implements ConfigMBean { @Override public String createFactoryConfiguration(String factoryPid, Map<String, String> properties) throws MBeanException { - Dictionary<String, String> dict = toDictionary(properties); + Dictionary<String, Object> dict = toDictionary(properties); return configRepo.createFactoryConfiguration(factoryPid, dict); } http://git-wip-us.apache.org/repos/asf/karaf/blob/ddeef77c/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 index 22311fb..1af3ce9 100644 --- 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 @@ -18,12 +18,16 @@ package org.apache.karaf.config.core.impl; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; +import java.util.UUID; import org.apache.felix.utils.properties.Properties; import org.apache.karaf.config.core.ConfigRepository; @@ -44,7 +48,7 @@ public class ConfigRepositoryImpl implements ConfigRepository { private File storage; public ConfigRepositoryImpl(ConfigurationAdmin configAdmin) { - this.configAdmin = configAdmin; + this(configAdmin, null); } public ConfigRepositoryImpl(ConfigurationAdmin configAdmin, File storage) { @@ -56,10 +60,9 @@ public class ConfigRepositoryImpl implements ConfigRepository { * @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 { + public void update(String pid, Dictionary<String, Object> props) throws IOException { LOGGER.trace("Update configuration {}", pid); - Configuration cfg = this.configAdmin.getConfiguration(pid, null); + Configuration cfg = configAdmin.getConfiguration(pid, null); cfg.update(props); try { updateStorage(pid, props); @@ -74,7 +77,7 @@ public class ConfigRepositoryImpl implements ConfigRepository { @Override public void delete(String pid) throws Exception { LOGGER.trace("Delete configuration {}", pid); - Configuration configuration = this.configAdmin.getConfiguration(pid, null); + Configuration configuration = configAdmin.getConfiguration(pid, null); configuration.delete(); try { deleteStorage(pid); @@ -91,26 +94,40 @@ public class ConfigRepositoryImpl implements ConfigRepository { } } - protected void updateStorage(String pid, Dictionary props) throws IOException { + private File getCfgFileFromProperties(Dictionary<String, Object> properties) throws URISyntaxException, MalformedURLException { + File cfgFile = null; + if (properties != null) { + Object val = properties.get(FILEINSTALL_FILE_NAME); + if (val instanceof URL) { + cfgFile = new File(((URL) val).toURI()); + } + if (val instanceof URI) { + cfgFile = new File((URI) val); + } + if (val instanceof String) { + cfgFile = new File(new URL((String) val).toURI()); + } + } + return cfgFile; + } + + protected void updateStorage(String pid, Dictionary<String, Object> props) throws IOException { if (storage != null) { - // get the cfg file - File cfgFile = new File(storage, pid + ".cfg"); Configuration cfg = configAdmin.getConfiguration(pid, null); - // update the cfg file depending of the configuration - if (cfg != null && cfg.getProperties() != null) { - Object val = cfg.getProperties().get(FILEINSTALL_FILE_NAME); - try { - if (val instanceof URL) { - cfgFile = new File(((URL) val).toURI()); - } - if (val instanceof URI) { - cfgFile = new File((URI) val); - } - if (val instanceof String) { - cfgFile = new File(new URL((String) val).toURI()); + // Initialize cfgFile with default location. Value gets overwritten when the existing configuration references a correct location. + File cfgFile = new File(storage, pid + ".cfg"); + if (cfg != null) { + Dictionary<String, Object> oldProps = cfg.getProperties(); + if (oldProps != null && oldProps.get(FILEINSTALL_FILE_NAME) != null) { + try { + cfgFile = getCfgFileFromProperties(oldProps); + if (cfgFile == null) { + throw new IOException("The configuration value '" + oldProps.get(FILEINSTALL_FILE_NAME) + + "' for ' + FILEINSTALL_FILE_NAME + ' does not represent a valid file location."); + } + } catch (URISyntaxException | MalformedURLException e) { + throw new IOException(e); } - } catch (Exception e) { - throw new IOException(e.getMessage(), e); } } LOGGER.trace("Update {}", cfgFile.getName()); @@ -149,31 +166,54 @@ public class ConfigRepositoryImpl implements ConfigRepository { * @see org.apache.karaf.shell.config.impl.ConfigRepository#getConfigProperties(java.lang.String) */ @Override - @SuppressWarnings("rawtypes") - public Dictionary getConfigProperties(String pid) throws IOException, InvalidSyntaxException { + public Dictionary<String, Object> getConfigProperties(String pid) throws IOException, InvalidSyntaxException { if (pid != null && configAdmin != null) { - Configuration configuration = this.configAdmin.getConfiguration(pid, null); - if(configuration != null) { - Dictionary props = configuration.getProperties(); - return (props != null) ? props : new Hashtable<String, String>(); + Configuration configuration = configAdmin.getConfiguration(pid, null); + if (configuration != null) { + Dictionary<String, Object> props = configuration.getProperties(); + return (props != null) ? props : new Hashtable<>(); } } return null; } + @Override public ConfigurationAdmin getConfigAdmin() { - return this.configAdmin; + return configAdmin; + } + + @Override + public String createFactoryConfiguration(String factoryPid, Dictionary<String, Object> properties) { + return createFactoryConfiguration(factoryPid, null, properties); } - @Override - public String createFactoryConfiguration(String factoryPid, Dictionary<String, ?> properties) { - try { - Configuration config = configAdmin.createFactoryConfiguration(factoryPid, null); - config.update(properties); - return config.getPid(); - } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); - } - } + @Override + public String createFactoryConfiguration(String factoryPid, String alias, Dictionary<String, Object> properties) { + try { + Configuration config = configAdmin.createFactoryConfiguration(factoryPid, null); + if (storage != null) { + // Check, whether a file location is already provided. + if (properties.get(FILEINSTALL_FILE_NAME) == null) { + // Create a synthetic unique alias for the factory + // configuration when it is unspecified. + if (alias == null) { + // Felix Fileinstall uses the hyphen as separator + // between factoryPid and alias. For safety reasons, all + // hyphens are removed from the generated UUID. + alias = UUID.randomUUID().toString().replaceAll("-", ""); + } + String cfgFileName = factoryPid + "-" + alias + ".cfg"; + File cfgFile = new File(storage, cfgFileName); + properties.put(FILEINSTALL_FILE_NAME, cfgFile.getCanonicalFile().toURI().toString()); + } + } + config.update(properties); + String pid = config.getPid(); + updateStorage(pid, properties); + return pid; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } } http://git-wip-us.apache.org/repos/asf/karaf/blob/ddeef77c/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 index 88fa6d5..d140f0a 100644 --- a/config/src/main/resources/org/apache/karaf/config/command/edit.txt +++ b/config/src/main/resources/org/apache/karaf/config/command/edit.txt @@ -6,7 +6,11 @@ The command above will also create a file etc/org.apache.karaf.sample.pid which 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. +In this case the config is created with a pid like myfactorypid.<generated id>. The file name is myfactorypid-<generated alias>.cfg. + +Create a factory config by factory pid and alias: + > config:edit --factory myfactorypid --alias myalias +In this case the config is created with a pid like myfactorypid.<generated id>. The file name is myfactorypid-myalias.cfg. Edit a config specified by an ldap query > config:edit '(myattribute=myvalue)' http://git-wip-us.apache.org/repos/asf/karaf/blob/ddeef77c/config/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java ---------------------------------------------------------------------- diff --git a/config/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java b/config/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java index e3f58b5..f17ba03 100644 --- a/config/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java +++ b/config/src/test/java/org/apache/karaf/config/command/UpdateCommandTest.java @@ -23,11 +23,11 @@ import static org.easymock.EasyMock.replay; import java.util.Dictionary; import java.util.Hashtable; -import junit.framework.TestCase; - import org.apache.karaf.config.core.ConfigRepository; import org.easymock.EasyMock; +import junit.framework.TestCase; + /** * Test cases for {@link EditCommand} */ @@ -52,13 +52,13 @@ public class UpdateCommandTest extends TestCase { command.execute(); EasyMock.verify(configRepo); } - + public void testupdateOnNewFactoryPid() throws Exception { Dictionary<String, Object> props = new Hashtable<String, Object>(); UpdateCommand command = new UpdateCommand(); ConfigRepository configRepo = EasyMock.createMock(ConfigRepository.class); - expect(configRepo.createFactoryConfiguration(EasyMock.eq(FACTORY_PID), EasyMock.eq(props))) + expect(configRepo.createFactoryConfiguration(EasyMock.eq(FACTORY_PID), EasyMock.eq(null), EasyMock.eq(props))) .andReturn(PID + ".35326647"); command.setConfigRepository(configRepo); @@ -70,7 +70,7 @@ public class UpdateCommandTest extends TestCase { EasyMock.verify(configRepo); } - private MockCommandSession createMockSessionForFactoryEdit(String pid, boolean isFactory, + private MockCommandSession createMockSessionForFactoryEdit(String pid, boolean isFactory, Dictionary<String, Object> props) { MockCommandSession session = new MockCommandSession(); session.put(ConfigCommandSupport.PROPERTY_CONFIG_PID, pid);