You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2014/03/07 15:30:10 UTC

svn commit: r1575269 - in /ace/trunk: org.apache.ace.agent.launcher/ org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/ org.apache.ace.agent.launcher/test/ org.apache.ace.agent.launcher/test/org/ org.apache.ace.agent.launcher/test/org/apa...

Author: jawi
Date: Fri Mar  7 14:30:09 2014
New Revision: 1575269

URL: http://svn.apache.org/r1575269
Log:
ACE-445 - allow launcher to set system properties:

- simplified the launcher in the handling and setting of configuration properties:
  * (almost) all configuration properties are now passed to the OSGi framework as 
    framework property, except for properties starting with 'system.', which are
    set as system property;
  * the 'framework.' prefix is deprecated, as it is no longer needed, but the
    launcher still will strip off this prefix if supplied;
  * agent configuration properties are now regarded as framework properties, and
    the agent now uses BundleContext#getProperty() to obtain its configuration
    options;
  * updated and clarified the help text of the launcher.
- allow configuration options to be set as *normal* arguments of the launcher 
  itself, as well as system property, so, '-Dfoo=bar' and 'foo=bar' both will
  work;
- simplified the semantics of the agent with respect to its configuration 
  handling: system properties are now regarded as default values that can be
  superseded by explicitly configured values (through framework properties, or
  explicit configuration). The '.retain' suffix for system properties to always
  supersede framework properties is removed, as it is quite difficult to explain
  and understand how they should work.


Added:
    ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/PropertyProvider.java   (with props)
    ace/trunk/org.apache.ace.agent.launcher/test/org/
    ace/trunk/org.apache.ace.agent.launcher/test/org/apache/
    ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/
    ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/agent/
    ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/agent/launcher/
    ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/agent/launcher/LauncherTest.java   (with props)
    ace/trunk/org.apache.ace.agent.launcher/test/test.properties   (with props)
Modified:
    ace/trunk/org.apache.ace.agent.launcher/   (props changed)
    ace/trunk/org.apache.ace.agent.launcher/.classpath
    ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/AgentBundleProvider.java
    ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleDirBundleProvider.java
    ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleProvider.java
    ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/Launcher.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/EventLoggerImplTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java

Propchange: ace/trunk/org.apache.ace.agent.launcher/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Fri Mar  7 14:30:09 2014
@@ -3,4 +3,5 @@ bin_test
 generated
 store
 bundle-cache
+test-output
 felix-cache

Modified: ace/trunk/org.apache.ace.agent.launcher/.classpath
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.launcher/.classpath?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent.launcher/.classpath (original)
+++ ace/trunk/org.apache.ace.agent.launcher/.classpath Fri Mar  7 14:30:09 2014
@@ -4,5 +4,6 @@
 	<classpathentry kind="src" output="bin_test" path="test"/>
 	<classpathentry kind="con" path="aQute.bnd.classpath.container"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>

Modified: ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/AgentBundleProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/AgentBundleProvider.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/AgentBundleProvider.java (original)
+++ ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/AgentBundleProvider.java Fri Mar  7 14:30:09 2014
@@ -18,24 +18,28 @@
  */
 package org.apache.ace.agent.launcher;
 
-import java.io.InputStream;
+import java.io.IOException;
+import java.net.URL;
 
 /**
  * {@link BundleProvider} for the core agent bundle.
  * 
  * @see META-INF/services/org.apache.ace.agent.launcher.BundleProvider
- * 
  */
 public class AgentBundleProvider implements BundleProvider {
+    private static final String AGENT_BUNDLE = "/org.apache.ace.agent.jar";
 
     @Override
-    public String[] getBundleNames() {
-        return new String[] { "org.apache.ace.agent" };
+    public URL[] getBundles(PropertyProvider properties) throws IOException {
+        URL agentURL = getClass().getResource(AGENT_BUNDLE);
+        if (agentURL == null) {
+            throw new RuntimeException("No agent bundle found!");
+        }
+        return new URL[] { agentURL };
     }
 
     @Override
-    public InputStream getInputStream(String name) {
-        return getClass().getClassLoader().getResourceAsStream(
-            "org.apache.ace.agent.jar");
+    public String toString() {
+        return getClass().getSimpleName();
     }
 }

Modified: ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleDirBundleProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleDirBundleProvider.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleDirBundleProvider.java (original)
+++ ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleDirBundleProvider.java Fri Mar  7 14:30:09 2014
@@ -1,52 +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.ace.agent.launcher;
 
 import java.io.File;
-import java.io.FileInputStream;
+import java.io.FilenameFilter;
 import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
+import java.net.URL;
+import java.util.Locale;
 
 /**
  * {@link BundleProvider} that loads bundles from a directory.
  * 
  * @see META-INF/services/org.apache.ace.agent.launcher.BundleProvider
- * 
  */
 public class BundleDirBundleProvider implements BundleProvider {
-
-    public static final String BUNDLE_DIR_PROPERTY = "agent.bundles.dir";
-    public static final String BUNDLE_DIR_DEFAULT = "bundle";
+    public static final String BUNDLE_DIR_PROPERTY = "launcher.bundles.dir";
+    public static final String BUNDLE_DIR_DEFAULT = "bundles";
 
     @Override
-    public String[] getBundleNames() {
-        File dir = getDir();
+    public URL[] getBundles(PropertyProvider properties) throws IOException {
+        File dir = getDir(properties);
         if (!dir.exists() || !dir.canRead() || !dir.isDirectory()) {
-            return new String[] {};
+            return new URL[0];
         }
 
-        File[] bundles = dir.listFiles();
-        List<String> names = new ArrayList<String>();
-        for (File bundle : bundles) {
-            names.add(bundle.getName());
+        File[] files = dir.listFiles(new FilenameFilter() {
+            @Override
+            public boolean accept(File dir, String name) {
+                return name.toLowerCase(Locale.ENGLISH).endsWith(".jar");
+            }
+        });
+        URL[] result = new URL[files.length];
+        for (int i = 0; i < files.length; i++) {
+            result[i] = files[i].toURI().toURL();
         }
-        return names.toArray(new String[names.size()]);
+        return result;
     }
 
     @Override
-    public InputStream getInputStream(String bundleName) throws IOException {
-        File dir = getDir();
-        if (!dir.exists() || !dir.canRead()) {
-            throw new IOException("No such bundle in dir " + dir.getAbsolutePath());
-        }
-        File bundle = new File(dir, bundleName);
-        if (!bundle.exists() || !bundle.canRead()) {
-            throw new IOException("No such bundle in dir " + dir.getAbsolutePath());
-        }
-        return new FileInputStream(bundle);
+    public String toString() {
+        return getClass().getSimpleName();
     }
 
-    private File getDir() {
-        return new File(System.getProperty(BUNDLE_DIR_PROPERTY, BUNDLE_DIR_DEFAULT));
+    private File getDir(PropertyProvider provider) throws IOException {
+        String dir = provider.getProperty(BUNDLE_DIR_PROPERTY);
+        if (dir == null) {
+            dir = BUNDLE_DIR_DEFAULT;
+        }
+        return new File(dir).getCanonicalFile();
     }
 }

Modified: ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleProvider.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleProvider.java (original)
+++ ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/BundleProvider.java Fri Mar  7 14:30:09 2014
@@ -19,26 +19,23 @@
 package org.apache.ace.agent.launcher;
 
 import java.io.IOException;
-import java.io.InputStream;
+import java.net.URL;
 import java.util.ServiceLoader;
 
 /**
  * {@link ServiceLoader} interface for launcher extension bundles providers.
- * 
  */
 public interface BundleProvider {
-
-    /**
-     * Return the bundle names.
-     * 
-     * @return The names
-     */
-    String[] getBundleNames();
-
     /**
-     * Return a bundle input stream
+     * Returns all the bundles to (pre-)install with the launcher.
      * 
-     * @return The input
+     * @param properties
+     *            the property provider to access configuration properties, cannot be <code>null</code>.
+     * @return an array with the URLs of bundles to install, never <code>null</code>.
+     * @throws IllegalArgumentException
+     *             in case the given provider was <code>null</code>;
+     * @throws IOException
+     *             in case of other I/O problems.
      */
-    InputStream getInputStream(String bundleName) throws IOException;
+    URL[] getBundles(PropertyProvider properties) throws IOException;
 }

Modified: ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/Launcher.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/Launcher.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/Launcher.java (original)
+++ ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/Launcher.java Fri Mar  7 14:30:09 2014
@@ -16,20 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.ace.agent.launcher;
 
+import java.io.Closeable;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.URISyntaxException;
+import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.ServiceLoader;
 
@@ -38,6 +40,7 @@ import org.apache.commons.cli.BasicParse
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.OptionBuilder;
 import org.apache.commons.cli.Options;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -46,227 +49,170 @@ import org.osgi.framework.launch.Framewo
 import org.osgi.framework.launch.FrameworkFactory;
 
 /**
- * A simple launcher, that launches the embedded OSGi framework together with a management agent. Additional bundles may be
- * installed by putting {@link BundleProvider} services on the classpath.
+ * A simple launcher, that launches the embedded OSGi framework together with a management agent. Additional bundles may
+ * be installed by putting {@link BundleProvider} services on the classpath.
  */
-public class Launcher {
+public class Launcher implements PropertyProvider {
+    private static final String SYSTEM_PREFIX = "system.";
+    private static final String FRAMEWORK_PREFIX = "framework.";
 
+    /**
+     * MAIN ENTRY POINT
+     */
     public static void main(String[] args) throws Exception {
+        Launcher launcher = new Launcher();
+        launcher.parseArgs(args);
+        launcher.run();
+    }
+
+    private Map<String, String> m_configuration;
+
+    /**
+     * @return the value of the property with the given key.
+     */
+    public String getProperty(String key) {
+        String value = m_configuration.get(key);
+        if (value == null) {
+            value = System.getProperty(key);
+        }
+        return value;
+    }
+
+    public Map<String, String> parseArgs(String... args) throws Exception {
         Options options = new Options();
-        options.addOption("a", "agent", true, "agent id (default handler)");
-        options.addOption("s", "serverurl", true, "server url (default handler)");
-        options.addOption("v", "verbose", false, "verbose logging");
-        options.addOption("c", "config", true, "configuration file (see below)");
-        options.addOption("h", "help", false, "print this message");
+        options.addOption(OptionBuilder.withDescription("the agent ID to use").hasArg().withArgName("ID").withLongOpt("agent").create('a'));
+        options.addOption(OptionBuilder.withDescription("the Apache ACE server URL(s) to use").hasArg().withArgName("URLs").withLongOpt("serverurl").create('s'));
+        options.addOption(OptionBuilder.withDescription("enable verbose logging").withLongOpt("verbose").create('v'));
+        options.addOption(OptionBuilder.withDescription("use configuration file").hasArg().withArgName("FILE").withLongOpt("config").create('c'));
+        options.addOption(OptionBuilder.withDescription("prints this message").withLongOpt("help").create('h'));
+
+        // Start from scratch...
+        Map<String, String> config = new HashMap<String, String>();
 
         CommandLineParser parser = new BasicParser();
-        CommandLine command = parser.parse(options, args);
+        CommandLine command = parser.parse(options, args, false /* stopAtNonOption */);
 
         if (command.hasOption("h")) {
             printHelp(options);
-            return;
+            System.exit(0);
         }
 
-        Map<String, String> configuration = new Hashtable<String, String>();
-
         // first map all default properties
-        Properties defaultProperties = loadDefaultProperties();
-        for (Object key : defaultProperties.keySet()) {
-            configuration.put((String) key, defaultProperties.getProperty((String) key));
-        }
+        propagateConfiguration(loadDefaultProperties(), config);
 
         // overwrite with user properties
         if (command.hasOption("c")) {
-            Properties userProperties = loadUserProperties(command.getOptionValue("c"));
-            if (userProperties != null) {
-                for (Object key : userProperties.keySet()) {
-                    configuration.put((String) key, userProperties.getProperty((String) key));
-                }
-            }
+            propagateConfiguration(loadUserProperties(command.getOptionValue("c")), config);
         }
 
-        // convenience debug override
+        // add all non-recognized command line options...
+        propagateConfiguration(command.getArgs(), config);
+
+        // convenience debug override...
         if (command.hasOption("v")) {
-            configuration.put("verbose", "true");
-            configuration.put(AgentConstants.CONFIG_LOGGING_LEVEL, "DEBUG");
+            config.put("verbose", "true");
+            config.put(AgentConstants.CONFIG_LOGGING_LEVEL, "DEBUG");
         }
 
-        // set server urls
+        // handle overrides...
         if (command.hasOption("s")) {
-            configuration.put("agent.discovery.serverurls", command.getOptionValue("s"));
+            config.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, command.getOptionValue("s"));
         }
-
-        // set agent id
         if (command.hasOption("a")) {
-            configuration.put("agent.identification.agentid", command.getOptionValue("a"));
+            config.put(AgentConstants.CONFIG_IDENTIFICATION_AGENTID, command.getOptionValue("a"));
         }
-        
-        new Launcher(configuration).run();
-    }
 
-    private static void printHelp(Options options) {
-        // if all else fails, this is our default jar name
-        String jarName = "org.apache.ace.agent.launcher.felix.jar";
-        // because we have to use an unofficial API to get to the command line
-        // to find the name of the jar that was started
-        String command = System.getProperty("sun.java.command");
-        if (command != null) {
-            String[] args = command.split(" ");
-            if (args.length > 0) {
-                jarName = args[0];
-            }
-        }
-        HelpFormatter formatter = new HelpFormatter();
-        formatter
-            .printHelp(
-                120,
-                "java -jar " + jarName + " [options]",
-                "\n\nOptions:\n\n", options,
-                "\n\nConfiguration file format:\n\n" +
-                "A configuration file that can contain framework or agent configuration settings. " +
-                "If you specify a certain setting both on the command line and in a configuration file, the command line takes precedence. " +
-                "Framework configuration should be prefixed with 'framework.' so for example 'framework.org.osgi.framework.bootdelegation' will become 'org.osgi.framework.bootdelegation'. " +
-                "Agent configuration starts with 'agent.' and will not be replaced. " +
-                "Available options are (not exclusive):\n" +
-                "agent.identification.agentid  : A name to uniquely identify the target\n" +
-                "agent.discovery.serverurls    : Location of the Apache ACE server\n" +
-                "agent.controller.syncinterval : Synchronization interval in seconds\n" +
-                "agent.controller.syncdelay    : Synchronization initial delay in seconds\n" +
-                "\n\nAlso, you can create a folder called 'bundle' and put bundles in that folder that will be started by the launcher.\n"
-                , false);
-        }
-
-    private static Properties loadDefaultProperties() throws IOException {
-        Properties properties = new Properties();
-        ClassLoader classloader = Launcher.class.getClassLoader();
-        InputStream inStream = classloader.getResourceAsStream("org/apache/ace/agent/launcher/launcher-defaults.properties");
-        try {
-
-            properties.load(inStream);
-            return properties;
-        }
-        finally {
-            inStream.close();
-        }
-    }
-
-    private static Properties loadUserProperties(String configFileArgument)
-        throws IOException {
-        File configFile = new File(configFileArgument);
-        if (!configFile.exists() || !configFile.isFile()
-            || !configFile.canRead()) {
-            System.err.println("Can not access configuration file : " + configFileArgument);
-            return null;
-        }
-        Properties properties = new Properties();
-        try {
-            properties.load(new FileInputStream(configFile));
-        }
-        catch (IOException e) {
-            System.err.println("Can not load configuration file : " + configFileArgument);
-            return null;
-        }
-        return properties;
-    }
-
-    private final Map<String, String> m_configuration;
-    private final boolean m_verbose;
-
-    public Launcher(Map<String, String> configuration) {
-        m_configuration = configuration;
-        m_verbose = (m_configuration.get("verbose") != null) && Boolean.parseBoolean(m_configuration.get("verbose"));
+        return (m_configuration = config);
     }
 
     /**
      * Main execution logic of the launcher; Start a framework, install bundles and pass configuration to the
      * {@link AgentFactory}.
      * 
-     * @throws Exception on failure
+     * @throws Exception
+     *             on failure
      */
     public void run() throws Exception {
-
+        int rc = 0;
         try {
             FrameworkFactory frameworkFactory = loadFrameworkFactory();
-            Map<String, String> frameworkProperties = createFrameworkProperties();
-            if (m_verbose) {
-                System.out.println("Launching OSGi framework\n factory\t: "
-                    + frameworkFactory.getClass().getName()
-                    + "\n properties\t: " + frameworkProperties);
-            }
+            BundleProvider[] bundleProviders = loadBundleProviders();
+
+            logVerbose("Launching OSGi framework\n- factory:\t%s\n- properties:\t%s\n- providers:\t%s\n",
+                frameworkFactory.getClass().getName(), m_configuration, Arrays.toString(bundleProviders));
 
-            Framework framework = frameworkFactory.newFramework(frameworkProperties);
-            BundleContext context = null;
+            Framework framework = frameworkFactory.newFramework(m_configuration);
             framework.init();
-            context = framework.getBundleContext();
 
-            BundleProvider[] bundleProviders = loadBundleProviders();
+            BundleContext context = framework.getBundleContext();
+
             for (BundleProvider bundleProvider : bundleProviders) {
                 installBundles(context, bundleProvider);
             }
 
-            for (Entry<String, String> entry : m_configuration.entrySet()) {
-                if (entry.getKey().startsWith(AgentConstants.CONFIG_KEY_NAMESPACE)) {
-                    System.setProperty(entry.getKey(), entry.getValue());
-                }
-            }
-
             framework.start();
 
-            if (m_verbose) {
-                System.out.println("Startup complete..");
-            }
+            logVerbose("Startup complete...");
+
             framework.waitForStop(0);
         }
         catch (Exception e) {
-            System.err.println(e.getMessage());
-            e.printStackTrace();
-            System.exit(1);
+            e.printStackTrace(System.err);
+            rc = 1;
         }
-        System.exit(0);
+
+        System.exit(rc);
+    }
+
+    /**
+     * @return the configuration
+     */
+    final Map<String, String> getConfiguration() {
+        return m_configuration;
     }
 
-    private Bundle[] installBundles(BundleContext context, BundleProvider extensionProvider) throws BundleException, IOException {
-        List<Bundle> bundles = new ArrayList<Bundle>();
-        for (String bundleName : extensionProvider.getBundleNames()) {
-            if (m_verbose) {
-                System.out.println("Installing bundle\t: " + bundleName);
+    private void close(Closeable resource) {
+        if (resource != null) {
+            try {
+                resource.close();
             }
-            InputStream inputStream = null;
+            catch (Exception exception) {
+                // Ignore, nothing we can do about this...
+            }
+        }
+    }
+
+    private Bundle[] installBundles(BundleContext context, BundleProvider bundleProvider) throws BundleException, IOException {
+        URL[] bundles = bundleProvider.getBundles(this);
+        List<Bundle> result = new ArrayList<Bundle>(bundles.length);
+        for (URL bundle : bundles) {
+            logVerbose("- installing:\t%s%n", bundle.getFile());
+
+            InputStream is = null;
             try {
-                inputStream = extensionProvider.getInputStream(bundleName);
-                bundles.add(context.installBundle(bundleName, inputStream));
+                is = bundle.openStream();
+                result.add(context.installBundle(bundle.toExternalForm(), is));
             }
             finally {
-                if (inputStream != null)
-                    inputStream.close();
+                close(is);
             }
         }
-        for (Bundle bundle : bundles) {
+        for (Bundle bundle : result) {
             bundle.start();
         }
-        return bundles.toArray(new Bundle[bundles.size()]);
+        return result.toArray(new Bundle[result.size()]);
     }
 
-    /**
-     * Load {@link FrameworkFactory} through the {@link ServiceLoader}.
-     * 
-     * @return the first factory
-     * @throws Exception on failure
-     */
-    private FrameworkFactory loadFrameworkFactory() throws Exception {
-        ServiceLoader<FrameworkFactory> frameworkFactoryLoader = ServiceLoader.load(FrameworkFactory.class);
-        Iterator<FrameworkFactory> frameworkFactoryIterator = frameworkFactoryLoader.iterator();
-        if (!frameworkFactoryIterator.hasNext()) {
-            throw new IllegalStateException("Unable to load any FrameworkFactory");
-        }
-        return frameworkFactoryIterator.next();
+    private boolean isVerbose() {
+        return (m_configuration.get("verbose") != null) && Boolean.parseBoolean(m_configuration.get("verbose"));
     }
 
     /**
      * Load {@link BundleProvider}s through the {@link ServiceLoader}.
      * 
      * @return list of providers
-     * @throws Exception on failure
+     * @throws Exception
+     *             on failure
      */
     private BundleProvider[] loadBundleProviders() throws Exception {
         ServiceLoader<BundleProvider> bundleFactoryLoader = ServiceLoader.load(BundleProvider.class);
@@ -278,21 +224,135 @@ public class Launcher {
         return bundelFactoryList.toArray(new BundleProvider[bundelFactoryList.size()]);
     }
 
-    /**
-     * Build the framework launch properties.
-     * 
-     * @return the launch properties
-     * @throws Exception on failure
-     */
-    private Map<String, String> createFrameworkProperties() throws Exception {
-        Map<String, String> frameworkProperties = new HashMap<String, String>();
-        for (Entry<String, String> entry : m_configuration.entrySet()) {
-            if (entry.getKey().startsWith("framework.")) {
-                String frameworkKey = entry.getKey().replaceFirst("framework.", "");
-                String frameworkValue = m_configuration.get(entry.getKey());
-                frameworkProperties.put(frameworkKey, frameworkValue);
+    private Properties loadDefaultProperties() throws IOException {
+        InputStream inStream = null;
+        try {
+            inStream = getClass().getResourceAsStream("launcher-defaults.properties");
+
+            Properties properties = new Properties();
+            properties.load(inStream);
+            return properties;
+        }
+        finally {
+            close(inStream);
+        }
+    }
+
+    private FrameworkFactory loadFrameworkFactory() throws IllegalStateException {
+        ServiceLoader<FrameworkFactory> frameworkFactoryLoader = ServiceLoader.load(FrameworkFactory.class);
+        Iterator<FrameworkFactory> frameworkFactoryIterator = frameworkFactoryLoader.iterator();
+        if (!frameworkFactoryIterator.hasNext()) {
+            throw new IllegalStateException("Unable to load any FrameworkFactory");
+        }
+        return frameworkFactoryIterator.next();
+    }
+
+    private Properties loadUserProperties(String configFile) throws IOException {
+        try {
+            Properties properties = new Properties();
+            properties.load(new FileInputStream(configFile));
+            return properties;
+        }
+        catch (Exception e) {
+            System.err.println("Can not load or access configuration file : " + configFile);
+            return null;
+        }
+    }
+
+    private void printHelp(Options options) {
+        // Since the main() method is in the same class, we can use the following trick to obtain the JAR name...
+        String jarName;
+        try {
+            jarName = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getName();
+        }
+        catch (URISyntaxException exception) {
+            jarName = getClass().getSimpleName();
+        }
+
+        PrintWriter pw = new PrintWriter(System.out);
+
+        new HelpFormatter().printHelp(pw, 120, "java -jar " + jarName, "\nOptions:", options, 4, 2, null, true);
+
+        pw.println("\n" +
+            "The configuration file provides the system and framework properties as well as the\n" +
+            "agent configuration settings. If you specify a setting both on the command line and in\n" + 
+            "a configuration file, the command line setting takes precedence. System properties can\n" + 
+            "be specified by prefixing the property name with 'system.', for example, to set the\n" +
+            "system property 'my.setting' one should specify it as 'system.my.setting'. All non-\n" +
+            "system properties (including the agent configuration) are regarded as framework\n" +
+            "properties, that is, will be passed to the OSGi framework.\n\n" +
+            "Common options are (see ACE documentation for extensive list):\n\n" +
+            "- agent.identification.agentid = <ID>\n" +
+            "    defines the target name as <name>, if not given 'defaultTargetID' will be used.\n" +
+            "    Note that the option '-a' overrides the agent ID in the configuration file!\n" +
+            "- agent.discovery.serverurls = <URL-1>,<URL-2>,...,<URL-N>\n" +
+            "    defines the location of the Apache ACE server(s), multiple servers can be given\n" +
+            "    by separating their URLs with commas. Multiple URLs are used in best-effort round\n" +
+            "    robin mode, that is, if the first URL fails, the second URL will be used, and so\n" +
+            "    on. If not supplied, the default URL of 'http://localhost:8080' is used.\n" +
+            "    Note that the option '-s' overrides the server URL(s) in the configuration file!\n" +
+            "- agent.logging.level = (DEBUG|INFO|WARNING|ERROR)\n" +
+            "    defines the log level of the agent. If not defined, 'INFO' is used as log level.\n" +
+            "    Note that passing the option '-v' to the launcher implicitly sets the log level\n" +
+            "    to 'DEBUG';\n" +
+            "- agent.controller.syncinterval = <N>\n" +
+            "    defines the synchronization interval (in seconds) in which the agent will\n" +
+            "    synchronize its state with the Apache ACE server;\n" +
+            "- agent.controller.syncdelay = <N>\n" +
+            "    defines the initial delay (in seconds) before the agent will start synchronization\n" +
+            "    with the Apache ACE server;\n" +
+            "- launcher.bundles.dir = <PATH>\n" +
+            "    defines the path where the launcher can find its initial set of bundles that should\n" +
+            "    be installed upon startup of the agent. If not specified, the launcher will look at\n" +
+            "    a directory called 'bundle' in the same directory as the launcher.\n");
+        pw.flush();
+        pw.close();
+    }
+
+    private void propagateConfiguration(Properties properties, Map<String, String> config) {
+        if (properties == null) {
+            return;
+        }
+        for (Object _key : properties.keySet()) {
+            String key = (String) _key;
+            String value = properties.getProperty(key);
+            if (key.startsWith(SYSTEM_PREFIX)) {
+                System.setProperty(key.substring(SYSTEM_PREFIX.length()), value);
+            }
+            else if (key.startsWith(FRAMEWORK_PREFIX)) {
+                // Strip off the framework prefix, as we pass all configuration options as fw property...
+                config.put(key.substring(FRAMEWORK_PREFIX.length()), value);
+            }
+            else {
+                config.put(key, value);
+            }
+        }
+    }
+
+    private void propagateConfiguration(String[] properties, Map<String, String> config) {
+        for (String property : properties) {
+            String[] kv = property.split("\\s*=\\s*", 2);
+
+            String key = kv[0].trim();
+            String value = (kv.length > 1) ? kv[1].trim() : "";
+
+            if (key.startsWith(SYSTEM_PREFIX)) {
+                // Never let system properties to propagate as fw property...
+                System.setProperty(key.substring(SYSTEM_PREFIX.length()), value);
+            }
+            else if (key.startsWith(FRAMEWORK_PREFIX)) {
+                // Strip off the framework prefix, as we pass all configuration options as framework option...
+                config.put(key.substring(FRAMEWORK_PREFIX.length()), value);
+            }
+            else {
+                config.put(key, value);
             }
         }
-        return frameworkProperties;
+    }
+
+    private void logVerbose(String msg, Object... args) {
+        if (isVerbose()) {
+            System.out.printf(msg, args);
+        }
     }
 }

Added: ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/PropertyProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/PropertyProvider.java?rev=1575269&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/PropertyProvider.java (added)
+++ ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/PropertyProvider.java Fri Mar  7 14:30:09 2014
@@ -0,0 +1,34 @@
+/*
+ * 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.ace.agent.launcher;
+
+/**
+ * Simple abstraction to retrieve property values.
+ */
+public interface PropertyProvider {
+
+    /**
+     * Returns the value of the property with the given key.
+     * 
+     * @param key
+     *            the key of the property to retrieve, should not be <code>null</code>.
+     * @return the property value, can be <code>null</code>.
+     */
+    String getProperty(String key);
+}

Propchange: ace/trunk/org.apache.ace.agent.launcher/src/org/apache/ace/agent/launcher/PropertyProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/agent/launcher/LauncherTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/agent/launcher/LauncherTest.java?rev=1575269&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/agent/launcher/LauncherTest.java (added)
+++ ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/agent/launcher/LauncherTest.java Fri Mar  7 14:30:09 2014
@@ -0,0 +1,93 @@
+/*
+ * 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.ace.agent.launcher;
+
+import static org.testng.Assert.*;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test cases for {@link Launcher}.
+ */
+public class LauncherTest {
+    private static final String TEST_PROPERTIES = "test/test.properties";
+
+    private static final String AGENT_DISCOVERY_SERVERURLS = "agent.discovery.serverurls";
+    private static final String AGENT_ID = "agent.identification.agentid";
+
+    @Test
+    public void testParseAgentIdOk() throws Exception {
+        Launcher launcher = new Launcher();
+
+        launcher.parseArgs("-a", "id1");
+        assertEquals(launcher.getConfiguration().get(AGENT_ID), "id1");
+
+        launcher.parseArgs(AGENT_ID.concat("=id2"));
+        assertEquals(launcher.getConfiguration().get(AGENT_ID), "id2");
+
+        launcher.parseArgs("-c", TEST_PROPERTIES);
+        assertEquals(launcher.getConfiguration().get(AGENT_ID), "myAgentID");
+
+        // -a supersedes agent.identification.agentid!
+        launcher.parseArgs("-a", "id1", AGENT_ID.concat("=id2"));
+        assertEquals(launcher.getConfiguration().get(AGENT_ID), "id1");
+
+        // command line version supersedes the value in config file!
+        launcher.parseArgs("-c", TEST_PROPERTIES, AGENT_ID.concat("=id2"));
+        assertEquals(launcher.getConfiguration().get(AGENT_ID), "id2");
+    }
+
+    @Test
+    public void testParseServerURLsOk() throws Exception {
+        Launcher launcher = new Launcher();
+
+        launcher.parseArgs("-s", "a,b,c");
+        assertEquals(launcher.getConfiguration().get(AGENT_DISCOVERY_SERVERURLS), "a,b,c");
+
+        launcher.parseArgs(AGENT_DISCOVERY_SERVERURLS.concat("=d,e,f"));
+        assertEquals(launcher.getConfiguration().get(AGENT_DISCOVERY_SERVERURLS), "d,e,f");
+
+        launcher.parseArgs("-c", TEST_PROPERTIES);
+        assertEquals(launcher.getConfiguration().get(AGENT_DISCOVERY_SERVERURLS), "http://localhost:1234/");
+
+        // -s supersedes agent.discovery.serverurls!
+        launcher.parseArgs("-s", "a,b,c", AGENT_DISCOVERY_SERVERURLS.concat("=d,e,f"));
+        assertEquals(launcher.getConfiguration().get(AGENT_DISCOVERY_SERVERURLS), "a,b,c");
+
+        // command line version supersedes the value in config file!
+        launcher.parseArgs("-c", TEST_PROPERTIES, AGENT_DISCOVERY_SERVERURLS.concat("=d,e,f"));
+        assertEquals(launcher.getConfiguration().get(AGENT_DISCOVERY_SERVERURLS), "d,e,f");
+    }
+
+    @Test
+    public void testParseSystemPropertyOk() throws Exception {
+        Launcher launcher = new Launcher();
+
+        launcher.parseArgs("system.property=value", "-c", TEST_PROPERTIES);
+        // The system properties shouldn't be included in the configuration...
+        assertNull(launcher.getConfiguration().get("property"));
+        assertNull(launcher.getConfiguration().get("prop2"));
+        // System properties never are accessible by their full name...
+        assertNull(launcher.getProperty("system.property"));
+        assertNull(launcher.getProperty("system.prop2"));
+        // System properties are only accessible through their stripped name...
+        assertEquals(launcher.getProperty("prop2"), "value2");
+        assertEquals(launcher.getProperty("property"), "value");
+    }
+}

Propchange: ace/trunk/org.apache.ace.agent.launcher/test/org/apache/ace/agent/launcher/LauncherTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/org.apache.ace.agent.launcher/test/test.properties
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.launcher/test/test.properties?rev=1575269&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent.launcher/test/test.properties (added)
+++ ace/trunk/org.apache.ace.agent.launcher/test/test.properties Fri Mar  7 14:30:09 2014
@@ -0,0 +1,6 @@
+agent.discovery.serverurls=http://localhost:1234/
+agent.identification.agentid=myAgentID
+prop1 = value1
+system.prop2 = value2
+prop3 = value3
+framework.prop4 = value4

Propchange: ace/trunk/org.apache.ace.agent.launcher/test/test.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java Fri Mar  7 14:30:09 2014
@@ -31,12 +31,6 @@ public interface AgentConstants {
     String CONFIG_KEY_NAMESPACE = "agent";
 
     /**
-     * Agent configuration property key postfix. When set to true, the system property will not overwrite an existing
-     * configuration value
-     */
-    String CONFIG_KEY_RETAIN = ".retain";
-
-    /**
      * Configuration loglevel for default logger. Should be a valid options s specified by {@link LoggingHandler.Levels}
      * , default is <code>INFO</code>.
      */
@@ -95,18 +89,6 @@ public interface AgentConstants {
     String CONFIG_CONTROLLER_CLASS = CONFIG_KEY_NAMESPACE + ".controller.class";
 
     /**
-     * Configuration option to disable the default controller. When set to true some other bundle control the agent's
-     * behavior. Should be <code>{true,false}</code>, default is <code>false</code>.
-     * <p>
-     * Note that this property is expected to be set as system or environment setting!
-     * </p>
-     * 
-     * @deprecated use {@link #CONFIG_CONTROLLER_CLASS} instead!
-     */
-    @Deprecated
-    String CONFIG_CONTROLLER_DISABLED = CONFIG_KEY_NAMESPACE + ".controller.disabled";
-
-    /**
      * Configuration option to set streaming behavior of the default controller. Should be <code>{true,false}</code>,
      * default is <code>true</code>.
      */

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java Fri Mar  7 14:30:09 2014
@@ -83,7 +83,9 @@ public interface ConfigurationHandler {
      * Return an unmodifiable copy of the configuration keys.
      * 
      * @return The set of keys
+     * @deprecated do not use, no replacement.
      */
+    @Deprecated
     Set<String> keySet();
 
     /**

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java Fri Mar  7 14:30:09 2014
@@ -115,7 +115,7 @@ public class Activator implements Bundle
         m_agentContext = new AgentContextImpl(bundleDataArea);
 
         m_agentContext.setHandler(LoggingHandler.class, new LoggingHandlerImpl());
-        m_agentContext.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
+        m_agentContext.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl(context));
         m_agentContext.setHandler(EventsHandler.class, new EventsHandlerImpl(context));
         m_agentContext.setHandler(ScheduledExecutorService.class, m_executorService);
         m_agentContext.setHandler(DownloadHandler.class, new DownloadHandlerImpl(bundleDataArea));

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java Fri Mar  7 14:30:09 2014
@@ -18,8 +18,6 @@
  */
 package org.apache.ace.agent.impl;
 
-import static org.apache.ace.agent.AgentConstants.CONFIG_KEY_NAMESPACE;
-import static org.apache.ace.agent.AgentConstants.CONFIG_KEY_RETAIN;
 import static org.apache.ace.agent.AgentConstants.EVENT_AGENT_CONFIG_CHANGED;
 
 import java.io.File;
@@ -31,7 +29,6 @@ import java.io.OutputStream;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -39,6 +36,7 @@ import java.util.concurrent.ConcurrentMa
 import java.util.concurrent.TimeUnit;
 
 import org.apache.ace.agent.ConfigurationHandler;
+import org.osgi.framework.BundleContext;
 
 /**
  * Default thread-safe {@link ConfigurationHandler} implementation.
@@ -49,39 +47,50 @@ public class ConfigurationHandlerImpl ex
     /** File name use for storage. */
     public static final String CONFIG_STORAGE_FILENAME = "config.properties";
 
+    private final BundleContext m_context;
+
     private ResettableTimer m_timer;
     private volatile ConcurrentMap<Object, Object> m_configProps;
 
-    public ConfigurationHandlerImpl() {
+    public ConfigurationHandlerImpl(BundleContext context) {
         super("configuration");
 
+        m_context = context;
+
         m_configProps = new ConcurrentHashMap<Object, Object>();
     }
 
     @Override
     public String get(String key, String defaultValue) {
-        String value = (String) m_configProps.get(key);
+        Object value = getProperty(key);
         if (value == null) {
             value = defaultValue;
         }
-        return value;
+        return String.valueOf(value);
     }
 
     @Override
     public boolean getBoolean(String key, boolean defaultValue) {
-        String value = get(key, "");
-        if (value.equals("")) {
+        Object value = getProperty(key);
+        if (value == null) {
             return defaultValue;
         }
-        return Boolean.parseBoolean(value);
+        return (value instanceof Boolean) ? ((Boolean) value).booleanValue() : Boolean.parseBoolean(String.valueOf(value));
     }
 
     @Override
     public int getInt(String key, int defaultValue) {
-        String value = get(key, "");
+        Object value = getProperty(key);
+        if (value == null) {
+            return defaultValue;
+        }
+
         try {
-            if (!"".equals(value)) {
-                return Integer.decode(value);
+            if (value instanceof Number) {
+                return ((Number) value).intValue();
+            }
+            else if (value instanceof String) {
+                return Integer.decode((String) value);
             }
         }
         catch (NumberFormatException exception) {
@@ -92,10 +101,17 @@ public class ConfigurationHandlerImpl ex
 
     @Override
     public long getLong(String key, long defaultValue) {
-        String value = get(key, "");
+        Object value = getProperty(key);
+        if (value == null) {
+            return defaultValue;
+        }
+
         try {
-            if (!"".equals(value)) {
-                return Long.decode(value);
+            if (value instanceof Number) {
+                return ((Number) value).longValue();
+            }
+            else if (value instanceof String) {
+                return Long.decode((String) value);
             }
         }
         catch (NumberFormatException exception) {
@@ -137,7 +153,6 @@ public class ConfigurationHandlerImpl ex
     @Override
     protected void onInit() throws Exception {
         loadConfig();
-        loadSystemProps();
 
         m_timer = new ResettableTimer(getExecutorService(), this, 5, TimeUnit.SECONDS);
     }
@@ -189,6 +204,14 @@ public class ConfigurationHandlerImpl ex
         return props;
     }
 
+    private Object getProperty(String key) {
+        Object result = m_configProps.get(key);
+        if (result == null) {
+            result = m_context.getProperty(key);
+        }
+        return result;
+    }
+
     private void loadConfig() throws IOException {
         InputStream input = null;
         try {
@@ -206,22 +229,6 @@ public class ConfigurationHandlerImpl ex
         }
     }
 
-    private void loadSystemProps() {
-        Properties sysProps = System.getProperties();
-
-        for (Entry<Object, Object> entry : sysProps.entrySet()) {
-            String key = (String) entry.getKey();
-
-            if (key.startsWith(CONFIG_KEY_NAMESPACE) && !key.endsWith(CONFIG_KEY_RETAIN)) {
-                boolean retain = Boolean.parseBoolean(sysProps.getProperty(key.concat(CONFIG_KEY_RETAIN)));
-
-                if (!retain || !m_configProps.containsKey(key)) {
-                    m_configProps.put(entry.getKey(), entry.getValue());
-                }
-            }
-        }
-    }
-
     private void scheduleStore() {
         if (!m_timer.schedule()) {
             logWarning("Cannot schedule task to store configuration. Executor is shut down!");

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConfigurationHandlerImplTest.java Fri Mar  7 14:30:09 2014
@@ -19,13 +19,13 @@
 package org.apache.ace.agent.impl;
 
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
 
 import java.lang.reflect.Method;
 
 import org.apache.ace.agent.AgentConstants;
 import org.apache.ace.agent.ConfigurationHandler;
 import org.apache.ace.agent.testutil.BaseAgentTest;
+import org.osgi.framework.BundleContext;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -34,10 +34,12 @@ import org.testng.annotations.Test;
  * Testing {@link ConfigurationHandlerImpl}.
  */
 public class ConfigurationHandlerImplTest extends BaseAgentTest {
+    private BundleContext m_context;
     private AgentContextImpl m_agentContextImpl;
 
     @BeforeMethod(alwaysRun = true)
     public void setUpAgain(Method method) throws Exception {
+        m_context = mockBundleContext();
         m_agentContextImpl = mockAgentContext(method.getName());
         replayTestMocks();
     }
@@ -51,7 +53,7 @@ public class ConfigurationHandlerImplTes
 
     @Test
     public void testConfigBooleanProps() throws Exception {
-        ConfigurationHandler configurationHandler = new ConfigurationHandlerImpl();
+        ConfigurationHandler configurationHandler = new ConfigurationHandlerImpl(m_context);
 
         resetConfigurationHandler(configurationHandler);
 
@@ -68,31 +70,27 @@ public class ConfigurationHandlerImplTes
 
     @Test
     public void testConfigClean() throws Exception {
-        ConfigurationHandler configurationHandler = new ConfigurationHandlerImpl();
+        ConfigurationHandler configurationHandler = new ConfigurationHandlerImpl(m_context);
 
         resetConfigurationHandler(configurationHandler);
 
         configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
 
-        assertNotNull(configurationHandler.keySet());
-        assertEquals(0, configurationHandler.keySet().size());
         assertEquals(configurationHandler.get("key1", "default1"), "default1");
 
         // should be persisted
-        configurationHandler = new ConfigurationHandlerImpl();
+        configurationHandler = new ConfigurationHandlerImpl(m_context);
 
         resetConfigurationHandler(configurationHandler);
 
         configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
 
-        assertNotNull(configurationHandler.keySet());
-        assertEquals(0, configurationHandler.keySet().size());
         assertEquals(configurationHandler.get("key1", "default1"), "default1");
     }
 
     @Test
     public void testConfigLongProps() throws Exception {
-        ConfigurationHandler configurationHandler = new ConfigurationHandlerImpl();
+        ConfigurationHandler configurationHandler = new ConfigurationHandlerImpl(m_context);
 
         resetConfigurationHandler(configurationHandler);
 
@@ -118,12 +116,10 @@ public class ConfigurationHandlerImplTes
 
         ConfigurationHandler configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
 
-        assertNotNull(configurationHandler.keySet());
-        assertEquals(2, configurationHandler.keySet().size());
         assertEquals(configurationHandler.get(systemKey1, "default1"), "value1");
         assertEquals(configurationHandler.get(systemKey2, "default2"), "value2");
 
-        // System props should be persisted
+        // System props should *not* be persisted, they are not in our control...
 
         System.clearProperty(systemKey1);
         System.clearProperty(systemKey2);
@@ -132,12 +128,10 @@ public class ConfigurationHandlerImplTes
 
         configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
 
-        assertNotNull(configurationHandler.keySet());
-        assertEquals(2, configurationHandler.keySet().size());
-        assertEquals(configurationHandler.get(systemKey1, "qqq"), "value1");
-        assertEquals(configurationHandler.get(systemKey2, "qqq"), "value2");
+        assertEquals(configurationHandler.get(systemKey1, "qux"), "qux");
+        assertEquals(configurationHandler.get(systemKey2, "quu"), "quu");
 
-        // System props should override by default
+        // System props should not override the configured values...
 
         System.setProperty(systemKey1, "value1");
         System.setProperty(systemKey2, "value2");
@@ -148,30 +142,24 @@ public class ConfigurationHandlerImplTes
 
         configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
 
-        assertNotNull(configurationHandler.keySet());
-        assertEquals(2, configurationHandler.keySet().size());
-        assertEquals(configurationHandler.get(systemKey1, "qqq"), "value1");
-        assertEquals(configurationHandler.get(systemKey2, "qqq"), "value2");
+        assertEquals(configurationHandler.get(systemKey1, "qux"), "newvalue1");
+        assertEquals(configurationHandler.get(systemKey2, "quu"), "newvalue2");
 
-        // System props should not override if retain is set
+        // System props should not override if explicitly configured values are present...
 
         System.setProperty(systemKey1, "valueX");
         System.setProperty(systemKey2, "valueY");
-        System.setProperty(systemKey1 + AgentConstants.CONFIG_KEY_RETAIN, "true");
-        System.setProperty(systemKey2 + AgentConstants.CONFIG_KEY_RETAIN, "true");
 
         resetConfigurationHandler();
 
         configurationHandler = m_agentContextImpl.getHandler(ConfigurationHandler.class);
 
-        assertNotNull(configurationHandler.keySet());
-        assertEquals(2, configurationHandler.keySet().size());
-        assertEquals(configurationHandler.get(systemKey1, "qqq"), "value1");
-        assertEquals(configurationHandler.get(systemKey2, "qqq"), "value2");
+        assertEquals(configurationHandler.get(systemKey1, "qqq"), "newvalue1");
+        assertEquals(configurationHandler.get(systemKey2, "qqq"), "newvalue2");
     }
 
     private void resetConfigurationHandler() throws Exception {
-        resetConfigurationHandler(new ConfigurationHandlerImpl());
+        resetConfigurationHandler(new ConfigurationHandlerImpl(m_context));
     }
 
     private void resetConfigurationHandler(ConfigurationHandler configurationHandler) throws Exception {

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java Fri Mar  7 14:30:09 2014
@@ -39,6 +39,7 @@ import org.apache.ace.agent.ConnectionHa
 import org.apache.ace.agent.EventsHandler;
 import org.apache.ace.agent.testutil.BaseAgentTest;
 import org.apache.ace.agent.testutil.TestWebServer;
+import org.osgi.framework.BundleContext;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -84,9 +85,11 @@ public class ConnectionHandlerImplTest e
         m_webServer.addServlet(new BasicAuthServlet(USERNAME, PASSWORD), "/basicauth/*");
         m_webServer.start();
 
+        BundleContext bc = mockBundleContext();
+        
         m_agentContext = mockAgentContext();
-        m_agentContext.setHandler(EventsHandler.class, new EventsHandlerImpl(mockBundleContext()));
-        m_agentContext.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
+        m_agentContext.setHandler(EventsHandler.class, new EventsHandlerImpl(bc));
+        m_agentContext.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl(bc));
         m_agentContext.setHandler(ConnectionHandler.class, new ConnectionHandlerImpl());
 
         replayTestMocks();

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java Fri Mar  7 14:30:09 2014
@@ -31,6 +31,7 @@ import org.apache.ace.agent.DiscoveryHan
 import org.apache.ace.agent.EventsHandler;
 import org.apache.ace.agent.testutil.BaseAgentTest;
 import org.apache.ace.agent.testutil.TestWebServer;
+import org.osgi.framework.BundleContext;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -56,11 +57,13 @@ public class DiscoveryHandlerImplTest ex
         m_availableURL = new URL("http://localhost:" + PORT);
         m_unavailableURL = new URL("http://localhost:9999");
 
+        BundleContext bc = mockBundleContext();
+
         m_agentContextImpl = mockAgentContext();
         m_agentContext = m_agentContextImpl;
         m_agentContextImpl.setHandler(DiscoveryHandler.class, new DiscoveryHandlerImpl());
-        m_agentContextImpl.setHandler(EventsHandler.class, new EventsHandlerImpl(mockBundleContext()));
-        m_agentContextImpl.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
+        m_agentContextImpl.setHandler(EventsHandler.class, new EventsHandlerImpl(bc));
+        m_agentContextImpl.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl(bc));
         m_agentContextImpl.setHandler(ConnectionHandler.class, new ConnectionHandlerImpl());
         replayTestMocks();
         m_agentContextImpl.start();

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/EventLoggerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/EventLoggerImplTest.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/EventLoggerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/EventLoggerImplTest.java Fri Mar  7 14:30:09 2014
@@ -32,6 +32,7 @@ import org.apache.ace.agent.FeedbackChan
 import org.apache.ace.agent.FeedbackHandler;
 import org.apache.ace.agent.RetryAfterException;
 import org.apache.ace.agent.testutil.BaseAgentTest;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkEvent;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -90,9 +91,11 @@ public class EventLoggerImplTest extends
     public void setUpOnceAgain() throws Exception {
         m_agentContext = mockAgentContext();
 
-        m_eventsHandler = new EventsHandlerImpl(mockBundleContext());
+        BundleContext bc = mockBundleContext();
+
+        m_eventsHandler = new EventsHandlerImpl(bc);
         m_agentContext.setHandler(EventsHandler.class, m_eventsHandler);
-        m_agentContext.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
+        m_agentContext.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl(bc));
         m_agentContext.setHandler(FeedbackHandler.class, new TestFeedbackHandler());
 
         replayTestMocks();

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/FeedbackHandlerImplTest.java Fri Mar  7 14:30:09 2014
@@ -31,6 +31,7 @@ import org.apache.ace.agent.Configuratio
 import org.apache.ace.agent.EventsHandler;
 import org.apache.ace.agent.FeedbackHandler;
 import org.apache.ace.agent.testutil.BaseAgentTest;
+import org.osgi.framework.BundleContext;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -52,9 +53,11 @@ public class FeedbackHandlerImplTest ext
         m_agentContextImpl = mockAgentContext();
         replayTestMocks();
 
+        BundleContext bc = mockBundleContext();
+
         m_agentContextImpl.setHandler(FeedbackHandler.class, new FeedbackHandlerImpl());
-        m_agentContextImpl.setHandler(EventsHandler.class, new EventsHandlerImpl(mockBundleContext()));
-        m_agentContextImpl.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
+        m_agentContextImpl.setHandler(EventsHandler.class, new EventsHandlerImpl(bc));
+        m_agentContextImpl.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl(bc));
 
         m_agentContextImpl.start();
     }

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java?rev=1575269&r1=1575268&r2=1575269&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java (original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java Fri Mar  7 14:30:09 2014
@@ -36,6 +36,8 @@ import org.apache.ace.agent.AgentContext
 import org.apache.ace.agent.AgentContextAware;
 import org.apache.ace.agent.ConfigurationHandler;
 import org.apache.ace.agent.impl.AgentContextImpl;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
 import org.osgi.framework.BundleContext;
 import org.testng.annotations.AfterClass;
 
@@ -105,6 +107,13 @@ public abstract class BaseAgentTest {
         BundleContext result = createNiceMock(BundleContext.class);
         expect(result.getDataFile(anyObject(String.class))).andReturn(dataFile).anyTimes();
         expect(result.createFilter(anyObject(String.class))).andReturn(null).anyTimes();
+        expect(result.getProperty(anyObject(String.class))).andAnswer(new IAnswer<String>() {
+            @Override
+            public String answer() throws Throwable {
+                String key = (String) EasyMock.getCurrentArguments()[0];
+                return System.getProperty(key);
+            }
+        }).anyTimes();
         replay(result);
         return result;
     }