ace-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r1521521 [1/3] - in /ace/trunk: org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/ org.apache.ace.agent/ org.apache.ace.agent/src/org/apache/ace/agent/ org.apache.ace.agent/src/org/apache/ace/agent/impl/ org.apache.ace.agent/test/or...
Date Tue, 10 Sep 2013 15:14:47 GMT
Author: jawi
Date: Tue Sep 10 15:14:46 2013
New Revision: 1521521

URL: http://svn.apache.org/r1521521
Log:
Code review on new ACE MA agent:

- added init() function to AgentContextAware to split the initialization
  from the starting of handlers/components. This way, we can make sure
  that, for example, event handlers are properly in place before sending
  configuration changes upon startup;
- implemented support for configuration change events on all relevant
  places;
- made the storing of configuration changes a little bit easier by using
  the same construct as used in the UserAdmin file store implementation
  of Felix;
- made the code thread-safe without heavy use of locks and monitors;
- some small changes in the integration tests to speed them up a little.


Modified:
    ace/trunk/org.apache.ace.agent/   (props changed)
    ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentDeploymentTest.java
    ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentExtensionTest.java
    ace/trunk/org.apache.ace.agent/bnd.bnd
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentContextAware.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/ConnectionHandler.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/EventListener.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/AgentContextImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentUpdateHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ComponentBase.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionUtil.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DependencyTrackerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DeploymentHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadHandleImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/EventLoggerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/EventsHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackChannelImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/FeedbackHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/IdentificationHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/LoggingHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/UpdateHandlerBase.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/FeedbackHandlerImplTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/TestWebServer.java

Propchange: ace/trunk/org.apache.ace.agent/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Sep 10 15:14:46 2013
@@ -4,3 +4,4 @@ generated
 store
 bundle-cache
 felix-cache
+test-output

Modified: ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentDeploymentTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentDeploymentTest.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentDeploymentTest.java (original)
+++ ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentDeploymentTest.java Tue Sep 10 15:14:46 2013
@@ -25,10 +25,10 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -37,6 +37,7 @@ import javax.servlet.http.HttpServletRes
 
 import org.apache.ace.agent.AgentConstants;
 import org.apache.ace.agent.AgentControl;
+import org.apache.ace.agent.ConfigurationHandler;
 import org.apache.ace.agent.EventListener;
 import org.apache.ace.agent.LoggingHandler;
 import org.apache.ace.builder.DeploymentPackageBuilder;
@@ -63,7 +64,6 @@ public class AgentDeploymentTest extends
 
     private enum Failure {
         EMPTY_STREAM, CORRUPT_STREAM, ABORT_STREAM, VERSIONS_RETRY_AFTER, DEPLOYMENT_RETRY_AFTER
-
     }
 
     private volatile TestDeploymentServlet m_servlet;
@@ -126,17 +126,24 @@ public class AgentDeploymentTest extends
         m_http.unregister("/deployment");
         m_http.unregister("/agent");
         m_http.unregister("/auditlog");
-    }
 
-    public void testDeployment() throws Exception {
+        resetAgentBundleState();
+    }
 
+    public void testStreamingDeployment() throws Exception {
         AgentControl control = getService(AgentControl.class);
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_LOGGING_LEVEL, LoggingHandler.Levels.DEBUG.name());
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_IDENTIFICATION_AGENTID, "007");
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_CONTROLLER_STREAMING, "true");
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_CONTROLLER_SYNCDELAY, "1");
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_CONTROLLER_SYNCINTERVAL, "2");
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_CONTROLLER_RETRIES, "2");
+
+        Map<String, String> props = new HashMap<String, String>();
+        props.put(AgentConstants.CONFIG_LOGGING_LEVEL, LoggingHandler.Levels.DEBUG.name());
+        props.put(AgentConstants.CONFIG_IDENTIFICATION_AGENTID, "007");
+        props.put(AgentConstants.CONFIG_CONTROLLER_STREAMING, "true");
+        props.put(AgentConstants.CONFIG_CONTROLLER_SYNCDELAY, "1");
+        props.put(AgentConstants.CONFIG_CONTROLLER_SYNCINTERVAL, "1");
+        props.put(AgentConstants.CONFIG_CONTROLLER_RETRIES, "2");
+
+        ConfigurationHandler configurationHandler = control.getConfigurationHandler();
+        configurationHandler.putAll(props);
+
         waitForInstalledVersion(Version.emptyVersion);
 
         expectSuccessfulDeployment(m_package1, Failure.VERSIONS_RETRY_AFTER);
@@ -145,21 +152,22 @@ public class AgentDeploymentTest extends
         expectSuccessfulDeployment(m_package4, Failure.CORRUPT_STREAM);
         expectSuccessfulDeployment(m_package5, Failure.ABORT_STREAM);
         expectSuccessfulDeployment(m_package6, null);
+    }
 
-        resetAgentBundleState();
+    public void testNonStreamingDeployment() throws Exception {
+        AgentControl control = getService(AgentControl.class);
+
+        Map<String, String> props = new HashMap<String, String>();
+        props.put(AgentConstants.CONFIG_LOGGING_LEVEL, LoggingHandler.Levels.DEBUG.name());
+        props.put(AgentConstants.CONFIG_IDENTIFICATION_AGENTID, "007");
+        props.put(AgentConstants.CONFIG_CONTROLLER_STREAMING, "false");
+        props.put(AgentConstants.CONFIG_CONTROLLER_SYNCDELAY, "1");
+        props.put(AgentConstants.CONFIG_CONTROLLER_SYNCINTERVAL, "1");
+        props.put(AgentConstants.CONFIG_CONTROLLER_RETRIES, "2");
+
+        ConfigurationHandler configurationHandler = control.getConfigurationHandler();
+        configurationHandler.putAll(props);
 
-        control = getService(AgentControl.class);
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_LOGGING_LEVEL, LoggingHandler.Levels.DEBUG.name());
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_IDENTIFICATION_AGENTID, "007");
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_CONTROLLER_STREAMING, "true");
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_CONTROLLER_SYNCDELAY, "2");
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_CONTROLLER_SYNCINTERVAL, "2");
-        control.getConfigurationHandler().put(AgentConstants.CONFIG_CONTROLLER_RETRIES, "2");
-        m_servlet.clearPackages();
-
-        control.getConfigurationHandler().put("ace.agent.controller.updateStreaming", "false");
-        control.getConfigurationHandler().put("ace.agent.identification.agentId", "007");
-        control.getConfigurationHandler().put("ace.agent.controller.syncDelay", "2");
         waitForInstalledVersion(Version.emptyVersion);
 
         expectSuccessfulDeployment(m_package1, Failure.VERSIONS_RETRY_AFTER);
@@ -181,6 +189,8 @@ public class AgentDeploymentTest extends
         waitForEventReceived("org/osgi/service/deployment/INSTALL");
         waitForEventReceived("org/osgi/service/deployment/COMPLETE");
         waitForInstalledVersion(dpackage.getVersion());
+
+        System.out.println("---");
     }
 
     private void waitForInstalledVersion(Version version) throws Exception {
@@ -231,51 +241,28 @@ public class AgentDeploymentTest extends
         jar.getManifest(); // Not sure whether this is needed...
         File file = File.createTempFile("testbundle", ".jar");
         jar.write(file);
+        b.close();
         return file;
     }
 
     private static class TestBundle {
-
-        private final String m_name;
-        private final Version m_version;
-        private final String[] m_headers;
         private final File m_file;
 
         public TestBundle(String name, Version version, String... headers) throws Exception {
-            m_name = name;
-            m_version = version;
-            m_headers = headers;
             m_file = createBundle(name, version, headers);
         }
 
-        public String getName() {
-            return m_name;
-        }
-
-        public Version getVersion() {
-            return m_version;
-        }
-
-        public String[] getHeaders() {
-            return m_headers;
-        }
-
         public File getFile() {
             return m_file;
         }
     }
 
     private static class TestPackage {
-
-        private final String m_name;
         private final Version m_version;
-        private final TestBundle[] m_bundles;
         private final File m_file;
 
         public TestPackage(String name, Version version, TestBundle... bundles) throws Exception {
-            m_name = name;
             m_version = version;
-            m_bundles = bundles;
 
             File[] files = new File[bundles.length];
             for (int i = 0; i < bundles.length; i++) {
@@ -284,29 +271,20 @@ public class AgentDeploymentTest extends
             m_file = createPackage(name, version, files);
         }
 
-        public String getName() {
-            return m_name;
-        }
-
         public Version getVersion() {
             return m_version;
         }
 
-        public TestBundle[] getBundles() {
-            return m_bundles;
-        }
-
         public File getFile() {
             return m_file;
         }
     }
 
     private static class TestEventListener implements EventListener {
-
-        private final List<String> m_topics = new ArrayList<String>();
+        private final CopyOnWriteArrayList<String> m_topics = new CopyOnWriteArrayList<String>();
 
         @Override
-        public synchronized void handle(String topic, Map<String, String> payload) {
+        public void handle(String topic, Map<String, String> payload) {
             System.out.println("Event: " + topic + " => " + payload);
             m_topics.add(topic);
         }
@@ -317,11 +295,12 @@ public class AgentDeploymentTest extends
     }
 
     private static class TestDeploymentServlet extends HttpServlet {
-
         private static final long serialVersionUID = 1L;
+
+        private static final String BACKOFF_TIME = "1";
+
         private final Map<String, TestPackage> m_packages = new HashMap<String, TestPackage>();
         private final String m_agentId;
-
         private Failure m_failure;
 
         public TestDeploymentServlet(String agentId) {
@@ -330,7 +309,6 @@ public class AgentDeploymentTest extends
 
         @Override
         protected synchronized void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
             String pathinfoTail = req.getPathInfo().replaceFirst("/" + m_agentId + "/versions/?", "");
             if (pathinfoTail.equals("")) {
                 sendVersions(resp);
@@ -348,18 +326,14 @@ public class AgentDeploymentTest extends
             m_packages.put(testPackage.getVersion().toString(), testPackage);
         }
 
-        public synchronized void clearPackages() {
-            m_packages.clear();
-        }
-
         public synchronized void setFailure(Failure failure) {
             m_failure = failure;
         }
 
         private void sendPackage(TestPackage dpackage, HttpServletResponse resp) throws IOException {
             if (m_failure == Failure.DEPLOYMENT_RETRY_AFTER) {
-                resp.addHeader("Retry-After", "3");
-                resp.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                resp.addHeader("Retry-After", BACKOFF_TIME);
+                resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Simulated server overload");
                 m_failure = null;
                 return;
             }
@@ -402,8 +376,8 @@ public class AgentDeploymentTest extends
 
         private void sendVersions(HttpServletResponse resp) throws IOException {
             if (m_failure == Failure.VERSIONS_RETRY_AFTER) {
-                resp.addHeader("Retry-After", "3");
-                resp.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                resp.addHeader("Retry-After", BACKOFF_TIME);
+                resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Simulated server overload");
                 m_failure = null;
                 return;
             }
@@ -418,7 +392,6 @@ public class AgentDeploymentTest extends
     }
 
     private static class TestUpdateServlet extends HttpServlet {
-
         private static final long serialVersionUID = 1L;
 
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
@@ -428,7 +401,6 @@ public class AgentDeploymentTest extends
     }
 
     private static class TestAuditlogServlet extends HttpServlet {
-
         private static final long serialVersionUID = 1L;
 
         // FIXME Ignoring auditlog.. but why do we get and empty send if we set range to high?

Modified: ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentExtensionTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentExtensionTest.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentExtensionTest.java (original)
+++ ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/AgentExtensionTest.java Tue Sep 10 15:14:46 2013
@@ -78,13 +78,16 @@ public class AgentExtensionTest extends 
     }
 
     private ServiceRegistration registerIdentification(final String id, final int rank) {
-        return m_bundleContext
-            .registerService(IdentificationHandler.class.getName(), new IdentificationHandler() {
-
+        return m_bundleContext.registerService(IdentificationHandler.class.getName(), new IdentificationHandler() {
                 @Override
                 public String getAgentId() {
                     return id;
                 }
+                
+                @Override
+                public String toString() {
+                    return id;
+                }
             }, new Properties() {
                 {
                     put(Constants.SERVICE_RANKING, rank);

Modified: ace/trunk/org.apache.ace.agent/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/bnd.bnd?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.agent/bnd.bnd Tue Sep 10 15:14:46 2013
@@ -39,10 +39,9 @@ javac.debug:  off
 	org.apache.ace.log.api;version=latest
 
 -sources false
--runfw: org.apache.felix.framework;version='[4.0.3,4.0.3]'
+-runfw: org.apache.felix.framework;version='[4.0,5.0)'
 -runee: JavaSE-1.6
 -runbundles: org.apache.felix.gogo.command,\
 	org.apache.felix.gogo.runtime,\
 	org.apache.felix.gogo.shell
--runproperties: agent.controller.syncdelay=1,\
-	agent.logging.level=DEBUG
\ No newline at end of file
+-runproperties: agent.controller.syncdelay=1

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=1521521&r1=1521520&r2=1521521&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 Tue Sep 10 15:14:46 2013
@@ -131,6 +131,12 @@ public interface AgentConstants {
     String CONFIG_CONNECTION_PASSWORD = CONFIG_KEY_NAMESPACE + ".connection.password";
 
     /**
+     * Configuration option to set the client-cert protocol for the default {@link ConnectionHandler}. Should be a
+     * string, default is <code>TLS</code>.
+     */
+    String CONFIG_CONNECTION_SSL_PROTOCOL = CONFIG_KEY_NAMESPACE + ".connection.sslProtocol";
+
+    /**
      * Configuration option to set the client-cert authentication keystore path for the default
      * {@link ConnectionHandler} . Should be a valid path, default is <code>""</code>.
      */

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentContextAware.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentContextAware.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentContextAware.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/AgentContextAware.java Tue Sep 10 15:14:46 2013
@@ -24,15 +24,34 @@ package org.apache.ace.agent;
 public interface AgentContextAware {
 
     /**
-     * Agent context started.
+     * Called when the agent context is initializing, and is called <em>before</em> {@link #start(AgentContext)}.
+     * <p>
+     * Use this method to register event listeners and/or perform other forms of initialization related tasks that need
+     * to be done prior to {@link #start(AgentContext)} being called.
+     * </p>
      * 
-     * @param agentContext The agent context
-     * @throws Exception If the component fails to start
+     * @param agentContext
+     *            the agent context that is initializing, never <code>null</code>.
+     * @throws Exception
+     *             if the component fails to initialize, which is logged and ignored by the agent.
+     */
+    void init(AgentContext agentContext) throws Exception;
+
+    /**
+     * Called when the agent context is started.
+     * 
+     * @param agentContext
+     *            the agent context that is started, never <code>null</code>.
+     * @throws Exception
+     *             if the component fails to start, which is logged and ignored by the agent.
      */
     void start(AgentContext agentContext) throws Exception;
 
     /**
-     * @throws Exception If the component fails to stop
+     * Called when the agent context is stopped.
+     * 
+     * @throws Exception
+     *             if the component fails to stop, which is logged and ignored by the agent.
      */
     void stop() throws Exception;
 }

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=1521521&r1=1521520&r2=1521521&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 Tue Sep 10 15:14:46 2013
@@ -18,6 +18,7 @@
  */
 package org.apache.ace.agent;
 
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -44,32 +45,47 @@ public interface ConfigurationHandler {
     /**
      * Retrieve the configuration value associated with the key, or the specified default.
      * 
-     * @param key The key, must not be <code>null</code>
-     * @param defaultValue The default value, must not be <code>null</code>
+     * @param key
+     *            The key, must not be <code>null</code>
+     * @param defaultValue
+     *            The default value, must not be <code>null</code>
      * @return The associated value if it exists, otherwise the default value
      */
     String get(String key, String defaultValue);
 
     /**
-     * Store a configuration value.
+     * Store a single configuration value.
      * 
-     * @param key The key, must not be <code>null</code>
-     * @param value The value, must not be <code>null</code>
+     * @param key
+     *            The key, must not be <code>null</code>
+     * @param value
+     *            The value, must not be <code>null</code>
      */
     void put(String key, String value);
 
     /**
+     * Store a configuration value.
+     * 
+     * @param props
+     *            the properties to put, cannot be <code>null</code>.
+     */
+    void putAll(Map<String, String> props);
+
+    /**
      * Remove a configuration value.
      * 
-     * @param key The key, must not be <code>null</code>
+     * @param key
+     *            The key, must not be <code>null</code>
      */
     void remove(String key);
 
     /**
      * Retrieve the configuration value associated with the key, or the specified default.
      * 
-     * @param key The key, must not be <code>null</code>
-     * @param defaultValue The default value
+     * @param key
+     *            The key, must not be <code>null</code>
+     * @param defaultValue
+     *            The default value
      * @return The associated value if it exists, otherwise the default value
      */
     long getLong(String key, long defaultValue);
@@ -77,16 +93,20 @@ public interface ConfigurationHandler {
     /**
      * Store a configuration value.
      * 
-     * @param key The key, must not be <code>null</code>
-     * @param value The value
+     * @param key
+     *            The key, must not be <code>null</code>
+     * @param value
+     *            The value
      */
     void putLong(String key, long value);
 
     /**
      * Retrieve the configuration value associated with the key, or the specified default.
      * 
-     * @param key The key, must not be <code>null</code>
-     * @param defaultValue The default value
+     * @param key
+     *            The key, must not be <code>null</code>
+     * @param defaultValue
+     *            The default value
      * @return The associated value if it exists, otherwise the default value
      */
     boolean getBoolean(String key, boolean defaultValue);
@@ -94,8 +114,10 @@ public interface ConfigurationHandler {
     /**
      * Store a configuration value.
      * 
-     * @param key The key, must not be <code>null</code>
-     * @param value The value
+     * @param key
+     *            The key, must not be <code>null</code>
+     * @param value
+     *            The value
      */
     void putBoolean(String key, boolean Value);
 }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java Tue Sep 10 15:14:46 2013
@@ -32,6 +32,18 @@ public interface ConnectionHandler {
      */
     enum Types {
         NONE, BASIC, CLIENTCERT;
+
+        public static Types parseType(String name) {
+            if (name == null) {
+                return Types.NONE;
+            }
+            try {
+                return Types.valueOf(name.toUpperCase().trim());
+            }
+            catch (Exception e) {
+                return Types.NONE;
+            }
+        }
     }
 
     /**

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/EventListener.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/EventListener.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/EventListener.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/EventListener.java Tue Sep 10 15:14:46 2013
@@ -1,3 +1,21 @@
+/*
+ * 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;
 
 import java.util.Map;

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=1521521&r1=1521520&r2=1521521&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 Tue Sep 10 15:14:46 2013
@@ -21,6 +21,7 @@ package org.apache.ace.agent.impl;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.ace.agent.AgentConstants;
 import org.apache.ace.agent.AgentControl;
@@ -35,22 +36,20 @@ import org.apache.ace.agent.FeedbackHand
 import org.apache.ace.agent.IdentificationHandler;
 import org.apache.ace.agent.LoggingHandler;
 import org.apache.ace.agent.impl.DependencyTrackerImpl.DependencyCallback;
-import org.apache.ace.agent.impl.DependencyTrackerImpl.LifecycleCallbacks;
+import org.apache.ace.agent.impl.DependencyTrackerImpl.LifecycleCallback;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.packageadmin.PackageAdmin;
 
 /**
- * 
+ * Bundle activator for ACE management agent.
  */
-public class Activator implements BundleActivator {
-
+public class Activator implements BundleActivator, LifecycleCallback {
     // managed state
     private volatile AgentContextImpl m_agentContext;
     private volatile ScheduledExecutorService m_executorService;
     private volatile ServiceRegistration m_agentControlRegistration;
-    private volatile BundleContext m_bundleContext;
     private volatile DependencyTrackerImpl m_dependencyTracker;
 
     // injected services
@@ -59,140 +58,153 @@ public class Activator implements Bundle
     private volatile DiscoveryHandler m_discoveryHandler;
     private volatile ConnectionHandler m_connectionHandler;
 
+    /**
+     * Called by OSGi framework when starting this bundle. It will start a bare dependency manager for tracking several
+     * of the (configurable) services. Once all dependencies are satisfied, {@link #componentStarted(BundleContext)}
+     * will be called.
+     */
     @Override
-    public void start(final BundleContext bundleContext) throws Exception {
-
-        m_bundleContext = bundleContext;
+    public void start(BundleContext bundleContext) throws Exception {
         m_executorService = Executors.newScheduledThreadPool(1, new InternalThreadFactory());
 
-        // FIXME minimize
-        m_dependencyTracker = new DependencyTrackerImpl(bundleContext, new LifecycleCallbacks() {
+        m_dependencyTracker = new DependencyTrackerImpl(bundleContext, this);
 
-            @Override
-            public void started() {
-                try {
-                    startAgent();
-                }
-                catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
+        addPackageAdminDependency(m_dependencyTracker);
 
-            @Override
-            public void stopped() {
-                try {
-                    stopAgent();
-                }
-                catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        });
+        if (Boolean.getBoolean(AgentConstants.CONFIG_IDENTIFICATION_DISABLED)) {
+            addIdenticationHandlerDependency(m_dependencyTracker);
+        }
 
-        m_dependencyTracker.addDependency(PackageAdmin.class, null, new DependencyCallback() {
-            @Override
-            public void updated(Object service) {
-                m_packageAdmin = (PackageAdmin) service;
-            }
-        });
+        if (Boolean.getBoolean(AgentConstants.CONFIG_DISCOVERY_DISABLED)) {
+            addDiscoveryHandlerDependency(m_dependencyTracker);
+        }
 
-        if (Boolean.parseBoolean(System.getProperty(AgentConstants.CONFIG_IDENTIFICATION_DISABLED))) {
-            m_dependencyTracker.addDependency(IdentificationHandler.class, null, new DependencyCallback() {
-                @Override
-                public void updated(Object service) {
-                    m_identificationHandler = (IdentificationHandler) service;
-                }
-            });
-        }
-
-        if (Boolean.parseBoolean(System.getProperty(AgentConstants.CONFIG_DISCOVERY_DISABLED))) {
-            m_dependencyTracker.addDependency(DiscoveryHandler.class, null, new DependencyCallback() {
-                @Override
-                public void updated(Object service) {
-                    m_discoveryHandler = (DiscoveryHandler) service;
-                }
-            });
-        }
-
-        if (Boolean.parseBoolean(System.getProperty(AgentConstants.CONFIG_CONNECTION_DISABLED))) {
-            m_dependencyTracker.addDependency(ConnectionHandler.class, null, new DependencyCallback() {
-                @Override
-                public void updated(Object service) {
-                    m_connectionHandler = (ConnectionHandler) service;
-                }
-            });
+        if (Boolean.getBoolean(AgentConstants.CONFIG_CONNECTION_DISABLED)) {
+            addConnectionHandlerDependency(m_dependencyTracker);
         }
 
         m_dependencyTracker.startTracking();
     }
 
+    /**
+     * Called by OSGi framework when stopping this bundle.
+     */
     @Override
     public void stop(BundleContext context) throws Exception {
-        m_dependencyTracker.stopTracking();
-        m_executorService.shutdownNow();
-        m_executorService = null;
+        try {
+            m_dependencyTracker.stopTracking();
+        }
+        finally {
+            m_executorService.shutdownNow();
+            m_executorService = null;
+        }
     }
 
-    private void startAgent() throws Exception {
+    /**
+     * Called by our {@link DependencyTrackerImpl} when all dependencies are satisfied.
+     */
+    public void componentStarted(BundleContext context) throws Exception {
+        m_agentContext = new AgentContextImpl(context.getDataFile(""));
 
-        m_agentContext = new AgentContextImpl(m_bundleContext.getDataFile(""));
         m_agentContext.setHandler(LoggingHandler.class, new LoggingHandlerImpl());
         m_agentContext.setHandler(ConfigurationHandler.class, new ConfigurationHandlerImpl());
-        m_agentContext.setHandler(EventsHandler.class, new EventsHandlerImpl(m_bundleContext));
+        m_agentContext.setHandler(EventsHandler.class, new EventsHandlerImpl(context));
         m_agentContext.setHandler(ScheduledExecutorService.class, m_executorService);
         m_agentContext.setHandler(DownloadHandler.class, new DownloadHandlerImpl());
-        m_agentContext.setHandler(DeploymentHandler.class, new DeploymentHandlerImpl(m_bundleContext, m_packageAdmin));
-        m_agentContext.setHandler(AgentUpdateHandler.class, new AgentUpdateHandlerImpl(m_bundleContext));
+        m_agentContext.setHandler(DeploymentHandler.class, new DeploymentHandlerImpl(context, m_packageAdmin));
+        m_agentContext.setHandler(AgentUpdateHandler.class, new AgentUpdateHandlerImpl(context));
         m_agentContext.setHandler(FeedbackHandler.class, new FeedbackHandlerImpl());
+        
+        IdentificationHandler identificationHandler = (m_identificationHandler != null) ? m_identificationHandler : new IdentificationHandlerImpl();
+        m_agentContext.setHandler(IdentificationHandler.class, identificationHandler);
 
-        if (m_identificationHandler != null) {
-            m_agentContext.setHandler(IdentificationHandler.class, m_identificationHandler);
-        }
-        else {
-            m_agentContext.setHandler(IdentificationHandler.class, new IdentificationHandlerImpl());
-        }
+        DiscoveryHandler discoveryHandler = (m_discoveryHandler != null) ? m_discoveryHandler : new DiscoveryHandlerImpl();
+        m_agentContext.setHandler(DiscoveryHandler.class, discoveryHandler);
 
-        if (m_discoveryHandler != null) {
-            m_agentContext.setHandler(DiscoveryHandler.class, m_discoveryHandler);
-        }
-        else {
-            m_agentContext.setHandler(DiscoveryHandler.class, new DiscoveryHandlerImpl());
-        }
+        ConnectionHandler connectionHandler = (m_connectionHandler != null) ? m_connectionHandler : new ConnectionHandlerImpl();
+        m_agentContext.setHandler(ConnectionHandler.class, connectionHandler);
+
+        m_agentContext.addComponent(new DefaultController());
+        m_agentContext.addComponent(new EventLoggerImpl(context));
+        
+        m_agentContext.start();
+
+        m_agentControlRegistration = context.registerService(AgentControl.class.getName(), new AgentControlImpl(m_agentContext), null);
+    }
 
-        if (m_connectionHandler != null) {
-            m_agentContext.setHandler(ConnectionHandler.class, m_connectionHandler);
+    /**
+     * Called by our {@link DependencyTrackerImpl} when one or more dependencies are no longer satisfied.
+     */
+    public void componentStopped(BundleContext context) throws Exception {
+        try {
+            if (m_agentControlRegistration != null) {
+                m_agentControlRegistration.unregister();
+            }
         }
-        else {
-            m_agentContext.setHandler(ConnectionHandler.class, new ConnectionHandlerImpl());
+        finally {
+            m_agentControlRegistration = null;
+
+            try {
+                m_agentContext.stop();
+            }
+            finally {
+                m_agentContext = null;
+            }
         }
+    }
 
-        m_agentContext.addComponent(new DefaultController());
-        m_agentContext.addComponent(new EventLoggerImpl(m_bundleContext));
-        m_agentContext.start();
+    private void addConnectionHandlerDependency(DependencyTrackerImpl tracker) throws Exception {
+        tracker.addDependency(ConnectionHandler.class, null, new DependencyCallback() {
+            @Override
+            public void updated(Object service) {
+                m_connectionHandler = (ConnectionHandler) service;
+            }
+        });
+    }
+
+    private void addDiscoveryHandlerDependency(DependencyTrackerImpl tracker) throws Exception {
+        tracker.addDependency(DiscoveryHandler.class, null, new DependencyCallback() {
+            @Override
+            public void updated(Object service) {
+                m_discoveryHandler = (DiscoveryHandler) service;
+            }
+        });
+    }
 
-        m_agentControlRegistration = m_bundleContext.registerService(
-            AgentControl.class.getName(), new AgentControlImpl(m_agentContext), null);
+    private void addIdenticationHandlerDependency(DependencyTrackerImpl tracker) throws Exception {
+        tracker.addDependency(IdentificationHandler.class, null, new DependencyCallback() {
+            @Override
+            public void updated(Object service) {
+                m_identificationHandler = (IdentificationHandler) service;
+            }
+        });
     }
 
-    private void stopAgent() throws Exception {
-        m_agentControlRegistration.unregister();
-        m_agentControlRegistration = null;
-        m_agentContext.stop();
-        m_agentContext = null;
+    private void addPackageAdminDependency(DependencyTrackerImpl tracker) throws Exception {
+        tracker.addDependency(PackageAdmin.class, null, new DependencyCallback() {
+            @Override
+            public void updated(Object service) {
+                m_packageAdmin = (PackageAdmin) service;
+            }
+        });
     }
 
     /**
      * Internal thread factory that assigns recognizable names to the threads it creates and sets them in daemon mode.
      */
-    static class InternalThreadFactory implements ThreadFactory {
-
-        private static final String m_name = "ACE Agent worker (%s)";
-        private int m_count = 0;
+    public static class InternalThreadFactory implements ThreadFactory {
+        private static final String NAME_TPL = "ACE Agent worker (%s)";
+        private final AtomicInteger m_count = new AtomicInteger();
 
         @Override
         public Thread newThread(Runnable r) {
-            Thread thread = new Thread(r, String.format(m_name, ++m_count));
+            Thread thread = new Thread(r, String.format(NAME_TPL, m_count.incrementAndGet()));
+            // TODO JaWi: is this really what we want? This means that these threads can be
+            // shutdown without any means to cleanup (can cause I/O errors, file corruption,
+            // a new world order, ...)
             thread.setDaemon(true);
+            // TODO JaWi: shouldn't we set the uncaught exception handler for these kind of
+            // threads? It would allow us to explicitly log something when things go wrong...
             return thread;
         }
     }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContextImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContextImpl.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContextImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContextImpl.java Tue Sep 10 15:14:46 2013
@@ -70,14 +70,23 @@ public class AgentContextImpl implements
     /**
      * Start the context.
      * 
-     * @throws Exception On failure.
+     * @throws Exception
+     *             On failure.
      */
     public void start() throws Exception {
+        // Make sure the agent-context is set for all known handlers before they are started, this way we can ensure
+        // they can properly call each other in their onStart() methods...
         for (Class<?> handlerIface : KNOWN_HANDLERS) {
             Object handler = m_handlers.get(handlerIface);
             if (handler == null) {
                 throw new IllegalStateException("Can not start context. Missing handler: " + handlerIface.getName());
             }
+            initAgentContextAware(handler);
+        }
+        for (Object component : m_components) {
+            initAgentContextAware(component);
+        }
+        for (Object handler : m_handlers.values()) {
             startAgentContextAware(handler);
         }
         for (Object component : m_components) {
@@ -88,7 +97,8 @@ public class AgentContextImpl implements
     /**
      * Stop the context.
      * 
-     * @throws Exception On failure.
+     * @throws Exception
+     *             On failure.
      */
     public void stop() throws Exception {
         for (Object component : m_components) {
@@ -106,43 +116,64 @@ public class AgentContextImpl implements
         return m_workDir;
     }
 
-    @SuppressWarnings("unchecked")
+    @Override
     public <T> T getHandler(Class<T> iface) {
-        return (T) m_handlers.get(iface);
+        Object result = m_handlers.get(iface);
+        return iface.cast(result);
     }
 
     /**
      * Set a handler on the context.
      * 
-     * @param iface The handler interface
-     * @param handler The handler implementation
+     * @param iface
+     *            The handler interface
+     * @param handler
+     *            The handler implementation
      */
-    public void setHandler(Class<?> iface, Object handler) {
-        if (!iface.isAssignableFrom(handler.getClass())) {
-            throw new IllegalArgumentException("Handler is not assignable to handler interface: "
-                + handler.getClass().getName() + " => " + iface.getName());
-        }
+    public <T> void setHandler(Class<T> iface, T handler) {
         m_handlers.put(iface, handler);
     }
 
     /**
-     * Add a component on the context.
+     * Add a component on the context. 
      * 
-     * @param component The component
+     * @param component
+     *            The component
      */
     public void addComponent(AgentContextAware component) {
         m_components.add(component);
     }
 
-    private void startAgentContextAware(Object object) throws Exception {
+    private void initAgentContextAware(Object object) throws Exception {
         if (object instanceof AgentContextAware) {
-            ((AgentContextAware) object).start(this);
+            try {
+                ((AgentContextAware) object).init(this);
+            }
+            catch (Exception exception) {
+                exception.printStackTrace();
+            }
         }
     }
 
-    private void stopAgentContextAware(Object object) throws Exception {
+    private void startAgentContextAware(Object object) {
         if (object instanceof AgentContextAware) {
-            ((AgentContextAware) object).stop();
+            try {
+                ((AgentContextAware) object).start(this);
+            }
+            catch (Exception exception) {
+                exception.printStackTrace();
+            }
+        }
+    }
+
+    private void stopAgentContextAware(Object object) {
+        if (object instanceof AgentContextAware) {
+            try {
+                ((AgentContextAware) object).stop();
+            }
+            catch (Exception exception) {
+                exception.printStackTrace();
+            }
         }
     }
 }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java Tue Sep 10 15:14:46 2013
@@ -30,10 +30,8 @@ import org.apache.ace.agent.Identificati
 
 /**
  * Implementation of the public agent control service.
- * 
  */
 public class AgentControlImpl implements AgentControl {
-
     private final AgentContext m_agentContext;
 
     public AgentControlImpl(AgentContext agentContext) throws IOException {

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentUpdateHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentUpdateHandlerImpl.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentUpdateHandlerImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentUpdateHandlerImpl.java Tue Sep 10 15:14:46 2013
@@ -18,6 +18,7 @@
  */
 package org.apache.ace.agent.impl;
 
+import static org.apache.ace.agent.impl.ConnectionUtil.*;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -55,39 +56,18 @@ public class AgentUpdateHandlerImpl exte
 
     public AgentUpdateHandlerImpl(BundleContext bundleContext) {
         super("agentupdate");
-        m_bundleContext = bundleContext;
-    }
-
-    @Override
-    public void onStart() throws Exception {
-        // at this point we know the agent has started, so any updater bundle that
-        // might still be running can be uninstalled
-        uninstallUpdaterBundle();
-    }
 
-    private void uninstallUpdaterBundle() throws BundleException {
-        for (Bundle b : m_bundleContext.getBundles()) {
-            if (UPDATER_SYMBOLICNAME.equals(b.getSymbolicName())) {
-                try {
-                    b.uninstall();
-                }
-                catch (BundleException e) {
-                    logError("Failed to uninstall updater bundle. Will try to stop it instead.", e);
-                    b.stop();
-                    throw e;
-                }
-            }
-        }
+        m_bundleContext = bundleContext;
     }
 
     @Override
-    public Version getInstalledVersion() {
-        return m_bundleContext.getBundle().getVersion();
+    public SortedSet<Version> getAvailableVersions() throws RetryAfterException, IOException {
+        return getAvailableVersions(getEndpoint(getServerURL(), getIdentification(), null));
     }
 
     @Override
-    public SortedSet<Version> getAvailableVersions() throws RetryAfterException, IOException {
-        return getAvailableVersions(getEndpoint(getServerURL(), getIdentification(), null));
+    public DownloadHandle getDownloadHandle(Version version) throws RetryAfterException, IOException {
+        return getDownloadHandle(getEndpoint(getServerURL(), getIdentification(), version));
     }
 
     @Override
@@ -96,8 +76,8 @@ public class AgentUpdateHandlerImpl exte
     }
 
     @Override
-    public DownloadHandle getDownloadHandle(Version version) throws RetryAfterException, IOException {
-        return getDownloadHandle(getEndpoint(getServerURL(), getIdentification(), version));
+    public Version getInstalledVersion() {
+        return m_bundleContext.getBundle().getVersion();
     }
 
     @Override
@@ -135,49 +115,50 @@ public class AgentUpdateHandlerImpl exte
         }
     }
 
+    @Override
+    public void onStart() throws Exception {
+        // at this point we know the agent has started, so any updater bundle that
+        // might still be running can be uninstalled
+        uninstallUpdaterBundle();
+    }
+
+    private Manifest createBundleManifest() {
+        Manifest manifest = new Manifest();
+        Attributes main = manifest.getMainAttributes();
+        main.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        main.put(new Attributes.Name("Bundle-ManifestVersion"), "2");
+        main.put(new Attributes.Name("Bundle-SymbolicName"), UPDATER_SYMBOLICNAME);
+        main.put(new Attributes.Name("Bundle-Version"), UPDATER_VERSION);
+        main.put(new Attributes.Name("Import-Package"), "org.osgi.framework");
+        main.put(new Attributes.Name("Bundle-Activator"), "org.apache.ace.agent.updater.Activator");
+        return manifest;
+    }
+
     /** Generates an input stream that contains a complete bundle containing our update code for the agent. */
     private InputStream generateBundle() throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
         InputStream is = null;
-        JarOutputStream jos = null;
-        ByteArrayOutputStream baos;
+        JarOutputStream os = null;
         try {
-            baos = new ByteArrayOutputStream();
-            Manifest manifest = new Manifest();
-            Attributes main = manifest.getMainAttributes();
-            main.put(Attributes.Name.MANIFEST_VERSION, "1.0");
-            main.put(new Attributes.Name("Bundle-ManifestVersion"), "2");
-            main.put(new Attributes.Name("Bundle-SymbolicName"), UPDATER_SYMBOLICNAME);
-            main.put(new Attributes.Name("Bundle-Version"), UPDATER_VERSION);
-            main.put(new Attributes.Name("Import-Package"), "org.osgi.framework");
-            main.put(new Attributes.Name("Bundle-Activator"), "org.apache.ace.agent.updater.Activator");
-            jos = new JarOutputStream(baos, manifest);
-            jos.putNextEntry(new JarEntry("org/apache/ace/agent/updater/Activator.class"));
             is = getClass().getResourceAsStream("/org/apache/ace/agent/updater/Activator.class");
-            byte[] buffer = new byte[1024];
-            int bytes;
-            while ((bytes = is.read(buffer)) != -1) {
-                jos.write(buffer, 0, bytes);
+
+            os = new JarOutputStream(baos, createBundleManifest());
+            os.putNextEntry(new JarEntry("org/apache/ace/agent/updater/Activator.class"));
+
+            try {
+                copy(is, os);
+            }
+            finally {
+                os.closeEntry();
             }
-            jos.closeEntry();
         }
         finally {
-            if (is != null) {
-                try {
-                    is.close();
-                }
-                catch (IOException e) {
-                }
-            }
-            if (jos != null) {
-                try {
-                    jos.close();
-                }
-                catch (IOException e) {
-                }
-            }
+            closeSilently(is);
+            closeSilently(os);
         }
-        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-        return bais;
+
+        return new ByteArrayInputStream(baos.toByteArray());
     }
 
     private URL getEndpoint(URL serverURL, String identification, Version version) {
@@ -188,4 +169,19 @@ public class AgentUpdateHandlerImpl exte
             throw new IllegalStateException(e);
         }
     }
+
+    private void uninstallUpdaterBundle() throws BundleException {
+        for (Bundle b : m_bundleContext.getBundles()) {
+            if (UPDATER_SYMBOLICNAME.equals(b.getSymbolicName())) {
+                try {
+                    b.uninstall();
+                }
+                catch (BundleException e) {
+                    logError("Failed to uninstall updater bundle. Will try to stop it instead.", e);
+                    b.stop();
+                    throw e;
+                }
+            }
+        }
+    }
 }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ComponentBase.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ComponentBase.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ComponentBase.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ComponentBase.java Tue Sep 10 15:14:46 2013
@@ -38,8 +38,8 @@ import org.apache.ace.agent.LoggingHandl
  * Convenience implementation base class for all {@link AgentContextAware} components, such as handlers & controllers.
  */
 public abstract class ComponentBase implements AgentContextAware {
-
     private final String m_identifier;
+    // Injected by AgentContextImpl...
     private volatile AgentContext m_context;
 
     public ComponentBase(String handlerIdentifier) {
@@ -47,30 +47,54 @@ public abstract class ComponentBase impl
     }
 
     @Override
+    public final void init(AgentContext agentContext) throws Exception {
+        if (agentContext == null) {
+            throw new IllegalArgumentException("Context must not be null");
+        }
+        if (m_context == null) {
+            m_context = agentContext;
+        }
+        onInit();
+    }
+
+    @Override
     public final void start(AgentContext agentContext) throws Exception {
         if (agentContext == null) {
             throw new IllegalArgumentException("Context must not be null");
         }
-        m_context = agentContext;
+        if (m_context == null) {
+            m_context = agentContext;
+        }
         onStart();
     }
 
     @Override
     public final void stop() throws Exception {
-        onStop();
-        m_context = null;
+        try {
+            onStop();
+        }
+        finally {
+            m_context = null;
+        }
     }
 
     protected final AgentContext getAgentContext() {
-        if (m_context == null)
+        if (m_context == null) {
             throw new IllegalStateException("Handler is not started: " + m_identifier);
+        }
         return m_context;
     }
 
+    protected void onInit() throws Exception {
+        // Nop
+    }
+
     protected void onStart() throws Exception {
+        // Nop
     }
 
     protected void onStop() throws Exception {
+        // Nop
     }
 
     protected final IdentificationHandler getIdentificationHandler() {

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=1521521&r1=1521520&r2=1521521&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 Tue Sep 10 15:14:46 2013
@@ -20,6 +20,7 @@ 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.impl.InternalConstants.AGENT_CONFIG_CHANGED;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -27,94 +28,94 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.Collections;
 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;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.ace.agent.ConfigurationHandler;
 
 /**
  * Default thread-safe {@link ConfigurationHandler} implementation.
  */
-// TODO performance; less locking using a map and read-write lock
-public class ConfigurationHandlerImpl extends ComponentBase implements ConfigurationHandler {
-
+public class ConfigurationHandlerImpl extends ComponentBase implements ConfigurationHandler, Runnable {
     /** Directory name use for storage. It is relative to the agent context work directory. */
     public static final String CONFIG_STORAGE_SUBDIR = "config";
-
     /** File name use for storage. */
     public static final String CONFIG_STORAGE_FILENAME = "config.properties";
 
-    private Properties m_configProps = null;
+    private final ResettableTimer m_timer;
+    private volatile ConcurrentMap<Object, Object> m_configProps;
 
     public ConfigurationHandlerImpl() {
         super("configuration");
+
+        m_configProps = new ConcurrentHashMap<Object, Object>();
+        m_timer = new ResettableTimer(this, 1, TimeUnit.SECONDS);
     }
 
     @Override
-    public void onStart() {
-        synchronized (this) {
-            loadSystemProps();
+    public String get(String key, String defaultValue) {
+        String value = (String) m_configProps.get(key);
+        if (value == null) {
+            value = defaultValue;
         }
+        return value;
     }
 
     @Override
-    public Set<String> keySet() {
-        Set<String> keySet = new HashSet<String>();
-        synchronized (this) {
-            ensureLoadConfig();
-            for (Object key : m_configProps.keySet()) {
-                keySet.add((String) key);
-            }
+    public boolean getBoolean(String key, boolean defaultValue) {
+        String value = get(key, "");
+        if (value.equals("")) {
+            return defaultValue;
         }
-        return Collections.unmodifiableSet(keySet);
+        return Boolean.parseBoolean(value);
     }
 
     @Override
-    public void put(String key, String value) {
-        synchronized (this) {
-            ensureLoadConfig();
-            String previous = (String) m_configProps.put(key, value);
-            if (previous == null || !previous.equals(value)) {
-                ensureStoreConfig();
-            }
+    public long getLong(String key, long defaultValue) {
+        String value = get(key, "");
+        if (value.equals("")) {
+            return defaultValue;
         }
+        return Long.parseLong(value);
     }
 
     @Override
-    public void remove(String key) {
-        synchronized (this) {
-            ensureLoadConfig();
-            Object value = m_configProps.remove(key);
-            if (value != null) {
-                getEventsHandler().postEvent("agent/config/CHANGED", new HashMap<String, String>());
-                ensureStoreConfig();
-            }
+    public Set<String> keySet() {
+        Set<String> keySet = new HashSet<String>();
+        for (Object key : m_configProps.keySet()) {
+            keySet.add((String) key);
         }
+        return keySet;
     }
 
     @Override
-    public String get(String key, String defaultValue) {
-        synchronized (this) {
-            ensureLoadConfig();
-            String value = (String) m_configProps.get(key);
-            if (value == null) {
-                value = defaultValue;
-            }
-            return value;
+    public void put(String key, String value) {
+        String previous = (String) m_configProps.put(key, value);
+        if (previous == null || !previous.equals(value)) {
+            fireConfigChangeEvent();
+            // causes the config to be written eventually...
+            scheduleStore();
         }
     }
 
     @Override
-    public long getLong(String key, long defaultValue) {
-        String value = get(key, "");
-        if (value.equals("")) {
-            return defaultValue;
-        }
-        return Long.parseLong(value);
+    public void putAll(Map<String, String> props) {
+        m_configProps.putAll(props);
+        fireConfigChangeEvent();
+        // causes the config to be written eventually...
+        scheduleStore();
+    }
+
+    @Override
+    public void putBoolean(String key, boolean value) {
+        put(key, String.valueOf(value));
     }
 
     @Override
@@ -123,94 +124,123 @@ public class ConfigurationHandlerImpl ex
     }
 
     @Override
-    public boolean getBoolean(String key, boolean defaultValue) {
-        String value = get(key, "");
-        if (value.equals("")) {
-            return defaultValue;
+    public void remove(String key) {
+        Object value = m_configProps.remove(key);
+        if (value != null) {
+            fireConfigChangeEvent();
+            // causes the config to be written eventually...
+            scheduleStore();
         }
-        return Boolean.parseBoolean(value);
     }
 
+    /**
+     * Called by {@link ResettableTimer} when a certain timeout has exceeded.
+     */
     @Override
-    public void putBoolean(String key, boolean value) {
-        put(key, String.valueOf(value));
+    public void run() {
+        try {
+            storeConfig();
+        }
+        catch (IOException exception) {
+            logWarning("Storing configuration failed!", exception);
+        }
     }
 
-    private void loadSystemProps() {
-        ensureLoadConfig();
-        for (Entry<Object, Object> entry : System.getProperties().entrySet()) {
-            String key = (String) entry.getKey();
-            if (key.startsWith(CONFIG_KEY_NAMESPACE) && !key.endsWith(CONFIG_KEY_RETAIN)) {
-                boolean retain = Boolean.parseBoolean(System.getProperties().getProperty(key + CONFIG_KEY_RETAIN));
-                if (!retain || !m_configProps.containsKey(key)) {
-                    m_configProps.put(entry.getKey(), entry.getValue());
-                }
-            }
-        }
-        ensureStoreConfig();
+    @Override
+    protected void onInit() throws Exception {
+        loadConfig();
+        loadSystemProps();
     }
 
-    private void ensureLoadConfig() {
-        if (m_configProps != null) {
-            return;
-        }
-        try {
-            m_configProps = new Properties();
-            loadConfig();
-        }
-        catch (IOException e) {
-            logError("Load config failed", e);
-            throw new IllegalStateException("Load config failed", e);
+    @Override
+    protected void onStart() throws Exception {
+        // Notify all interested listeners about this...
+        fireConfigChangeEvent();
+    }
+
+    @Override
+    protected void onStop() throws Exception {
+        if (!m_timer.isShutDown()) {
+            m_timer.shutDown();
         }
+        // Make sure the configuration is written one last time...
+        storeConfig();
     }
 
-    private void ensureStoreConfig() {
-        if (m_configProps == null) {
-            return;
+    private void fireConfigChangeEvent() {
+        Map<String, String> props = new HashMap<String, String>();
+        for (Map.Entry<Object, Object> entry : m_configProps.entrySet()) {
+            props.put((String) entry.getKey(), (String) entry.getValue());
         }
-        try {
-            storeConfig();
+        getEventsHandler().postEvent(AGENT_CONFIG_CHANGED, props);
+    }
+
+    private File getConfigDir() throws IOException {
+        File dir = new File(getAgentContext().getWorkDir(), CONFIG_STORAGE_SUBDIR);
+        if (!dir.exists() && !dir.mkdir()) {
+            throw new IOException("Unable to acces configuration directory: " + dir.getAbsolutePath());
         }
-        catch (IOException e) {
-            logError("Storing config failed", e);
-            throw new IllegalStateException("Store config failed", e);
+        return dir;
+    }
+
+    private File getConfigFile() throws IOException {
+        File file = new File(getConfigDir(), CONFIG_STORAGE_FILENAME);
+        if (!file.exists() && !file.createNewFile()) {
+            throw new IOException("Unable to acces configuration file: " + file.getAbsolutePath());
         }
+        return file;
     }
 
     private void loadConfig() throws IOException {
-        File configFile = getConfigFile();
-        InputStream input = new FileInputStream(configFile);
+        InputStream input = null;
         try {
-            m_configProps.clear();
-            m_configProps.load(input);
+            input = new FileInputStream(getConfigFile());
+
+            Properties props = new Properties();
+            props.load(input);
+
+            m_configProps = new ConcurrentHashMap<Object, Object>(props);
         }
         finally {
-            input.close();
+            if (input != null) {
+                input.close();
+            }
         }
     }
 
+    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() {
+        m_timer.schedule();
+    }
+
     private void storeConfig() throws IOException {
         OutputStream output = null;
         try {
             output = new FileOutputStream(getConfigFile());
-            m_configProps.store(output, "ACE Agent configuration");
+
+            Properties props = new Properties();
+            props.putAll(m_configProps);
+            props.store(output, "ACE Agent configuration");
         }
         finally {
-            output.close();
+            if (output != null) {
+                output.close();
+            }
         }
     }
-
-    private File getConfigFile() throws IOException {
-        File file = new File(getConfigDir(), CONFIG_STORAGE_FILENAME);
-        if (!file.exists() && !file.createNewFile())
-            throw new IOException("Unable to acces configuration file: " + file.getAbsolutePath());
-        return file;
-    }
-
-    private File getConfigDir() throws IOException {
-        File dir = new File(getAgentContext().getWorkDir(), CONFIG_STORAGE_SUBDIR);
-        if (!dir.exists() && !dir.mkdir())
-            throw new IOException("Unable to acces configuration directory: " + dir.getAbsolutePath());
-        return dir;
-    }
 }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java Tue Sep 10 15:14:46 2013
@@ -24,7 +24,8 @@ import static org.apache.ace.agent.Agent
 import static org.apache.ace.agent.AgentConstants.CONFIG_CONNECTION_PASSWORD;
 import static org.apache.ace.agent.AgentConstants.CONFIG_CONNECTION_TRUSTFILE;
 import static org.apache.ace.agent.AgentConstants.CONFIG_CONNECTION_TRUSTPASS;
-import static org.apache.ace.agent.AgentConstants.CONFIG_CONNECTION_USERNAME;
+import static org.apache.ace.agent.AgentConstants.*;
+import static org.apache.ace.agent.impl.InternalConstants.AGENT_CONFIG_CHANGED;
 
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -35,6 +36,7 @@ import java.net.URLConnection;
 import java.security.GeneralSecurityException;
 import java.security.KeyStore;
 import java.security.SecureRandom;
+import java.util.Map;
 
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.KeyManager;
@@ -45,12 +47,36 @@ import javax.net.ssl.TrustManagerFactory
 import javax.xml.bind.DatatypeConverter;
 
 import org.apache.ace.agent.ConnectionHandler;
+import org.apache.ace.agent.EventListener;
 
 /**
  * Default thread-safe {@link ConnectionHandler} implementation with support for BASIC authentication and HTTPS client
  * certificates.
  */
-public class ConnectionHandlerImpl extends ComponentBase implements ConnectionHandler {
+public class ConnectionHandlerImpl extends ComponentBase implements ConnectionHandler, EventListener {
+
+    private static class UrlCredentials {
+        private final Types m_type;
+        private final Object[] m_credentials;
+
+        public UrlCredentials(Types type, Object... credentials) {
+            m_type = type;
+            m_credentials = credentials.clone();
+        }
+
+        public Object[] getCredentials() {
+            return m_credentials;
+        }
+
+        public Types getType() {
+            return m_type;
+        }
+    }
+
+    private static final UrlCredentials EMPTY_CREDENTIALS = new UrlCredentials(Types.NONE);
+    private static final String DEFAULT_PROTOCOL = "TLS";
+
+    private volatile UrlCredentials m_credentials;
 
     public ConnectionHandlerImpl() {
         super("connection");
@@ -58,161 +84,154 @@ public class ConnectionHandlerImpl exten
 
     @Override
     public URLConnection getConnection(URL url) throws IOException {
-        URLConnection connection = (HttpURLConnection) url.openConnection();
-        UrlCredentials credentials = getCredentials();
+        URLConnection connection = url.openConnection();
+
+        UrlCredentials credentials = m_credentials;
         if (credentials != null) {
-            if (credentials != null && credentials.getType() == Types.BASIC)
+            if (Types.BASIC == credentials.getType()) {
                 applyBasicAuthentication(connection, credentials.getCredentials());
-
-            else if (credentials != null && credentials.getType() == Types.CLIENTCERT) {
+            }
+            else if (Types.CLIENTCERT == credentials.getType()) {
                 applyClientCertificate(connection, credentials.getCredentials());
             }
         }
+
         return connection;
     }
 
-    private final String getBasicAuthCredentials(Object[] values) {
-        if ((values == null) || values.length < 2) {
-            throw new IllegalArgumentException("Insufficient credentials passed: expected 2 values!");
+    @Override
+    public void handle(String topic, Map<String, String> payload) {
+        if (AGENT_CONFIG_CHANGED.equals(topic)) {
+            m_credentials = getCredentials(payload);
         }
+    }
 
-        StringBuilder sb = new StringBuilder();
-        if (values[0] instanceof String) {
-            sb.append((String) values[0]);
-        }
-        else if (values[0] instanceof byte[]) {
-            sb.append(new String((byte[]) values[0]));
-        }
-        sb.append(':');
-        if (values[1] instanceof String) {
-            sb.append((String) values[1]);
-        }
-        else if (values[1] instanceof byte[]) {
-            sb.append(new String((byte[]) values[1]));
-        }
+    @Override
+    protected void onInit() throws Exception {
+        getEventsHandler().addListener(this);
+    }
 
-        return "Basic " + DatatypeConverter.printBase64Binary(sb.toString().getBytes());
+    @Override
+    protected void onStop() throws Exception {
+        getEventsHandler().removeListener(this);
     }
 
     private void applyBasicAuthentication(URLConnection conn, Object[] values) {
         if (conn instanceof HttpURLConnection) {
-            conn.setRequestProperty("Authorization", getBasicAuthCredentials(values));
+            String encodedCreds = (String) values[0];
+            conn.setRequestProperty("Authorization", "Basic ".concat(encodedCreds));
         }
     }
 
     private void applyClientCertificate(URLConnection conn, Object[] values) {
         if (conn instanceof HttpsURLConnection) {
-            ((HttpsURLConnection) conn).setSSLSocketFactory(((SSLContext) values[0]).getSocketFactory());
+            SSLContext sslContext = (SSLContext) values[0];
+            ((HttpsURLConnection) conn).setSSLSocketFactory(sslContext.getSocketFactory());
         }
     }
 
-    public UrlCredentials getCredentials() {
-
-        String configValue = getConfigStringValue(CONFIG_CONNECTION_AUTHTYPE);
-        Types authType = getType(configValue == null ? "" : configValue.trim().toUpperCase());
-        if (authType == null || authType == Types.NONE) {
-            return UrlCredentials.EMPTY_CREDENTIALS;
+    private String encodeBasicAuthCredentials(String username, String password) {
+        StringBuilder sb = new StringBuilder();
+        if (username != null) {
+            sb.append(username);
         }
-
-        if (authType == Types.BASIC) {
-            String username = getConfigStringValue(CONFIG_CONNECTION_USERNAME);
-            String password = getConfigStringValue(CONFIG_CONNECTION_PASSWORD);
-            return new UrlCredentials(Types.BASIC, new Object[] { username == null ? "" : username, password == null ? "" : password });
+        sb.append(':');
+        if (password != null) {
+            sb.append(password);
         }
 
-        if (authType == Types.CLIENTCERT) {
-            String keystoreFile = getConfigStringValue(CONFIG_CONNECTION_KEYFILE);
-            String keystorePass = getConfigStringValue(CONFIG_CONNECTION_KEYPASS);
-            String truststoreFile = getConfigStringValue(CONFIG_CONNECTION_TRUSTFILE);
-            String truststorePass = getConfigStringValue(CONFIG_CONNECTION_TRUSTPASS);
+        return DatatypeConverter.printBase64Binary(sb.toString().getBytes());
+    }
 
-            // TODO This is expensive. Can we cache?
-            try {
-                KeyManager[] keyManagers = getKeyManagerFactory(keystoreFile, keystorePass);
-                TrustManager[] trustManagers = getTrustManagerFactory(truststoreFile, truststorePass);
-                SSLContext context = SSLContext.getInstance("TLS");
-                context.init(keyManagers, trustManagers, new SecureRandom());
-                return new UrlCredentials(Types.CLIENTCERT, new Object[] { context });
-            }
-            catch (Exception e) {
-                // TODO log
-            }
+    private UrlCredentials getCredentials(Map<String, String> config) {
+        String configValue = config.get(CONFIG_CONNECTION_AUTHTYPE);
+
+        Types authType = Types.parseType(configValue);
+        switch (authType) {
+            case BASIC:
+                String username = config.get(CONFIG_CONNECTION_USERNAME);
+                String password = config.get(CONFIG_CONNECTION_PASSWORD);
+
+                return new UrlCredentials(authType, encodeBasicAuthCredentials(username, password));
+
+            case CLIENTCERT:
+                String keystoreFile = config.get(CONFIG_CONNECTION_KEYFILE);
+                String keystorePass = config.get(CONFIG_CONNECTION_KEYPASS);
+                String truststoreFile = config.get(CONFIG_CONNECTION_TRUSTFILE);
+                String truststorePass = config.get(CONFIG_CONNECTION_TRUSTPASS);
+                String sslProtocol = config.get(CONFIG_CONNECTION_SSL_PROTOCOL);
+                if (sslProtocol == null || "".equals(sslProtocol.trim())) {
+                    sslProtocol = DEFAULT_PROTOCOL;
+                }
+
+                try {
+                    KeyManager[] keyManagers = getKeyManagerFactory(keystoreFile, keystorePass);
+                    TrustManager[] trustManagers = getTrustManagerFactory(truststoreFile, truststorePass);
+
+                    SSLContext context = SSLContext.getInstance(sslProtocol);
+                    context.init(keyManagers, trustManagers, new SecureRandom());
+
+                    return new UrlCredentials(authType, context);
+                }
+                catch (Exception e) {
+                    logError("Failed to get credentials for client certificate!", e);
+                }
+
+            case NONE:
+            default:
+                return EMPTY_CREDENTIALS;
         }
-        return null;
     }
 
-    private String getConfigStringValue(String key) {
-        return getConfigurationHandler().get(key, null);
-    }
+    private KeyManager[] getKeyManagerFactory(String keystoreFile, String storePass) throws IOException, GeneralSecurityException {
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
 
-    private static KeyManager[] getKeyManagerFactory(String keystoreFile, String storePass) throws IOException, GeneralSecurityException {
-        InputStream keyInput = null;
+        InputStream is = null;
         try {
-            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
-            keyInput = new FileInputStream(keystoreFile);
-            keyStore.load(keyInput, storePass.toCharArray());
-            keyManagerFactory.init(keyStore, storePass.toCharArray());
-            return keyManagerFactory.getKeyManagers();
+            is = new FileInputStream(keystoreFile);
+
+            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+            ks.load(is, storePass.toCharArray());
+
+            kmf.init(ks, storePass.toCharArray());
+
+            return kmf.getKeyManagers();
         }
         finally {
             try {
-                if (keyInput != null)
-                    keyInput.close();
+                if (is != null) {
+                    is.close();
+                }
             }
             catch (IOException e) {
-                // TODO log
+                // Ignore; we're only reading from it...
             }
         }
     }
 
-    private static TrustManager[] getTrustManagerFactory(String truststoreFile, String storePass) throws IOException, GeneralSecurityException {
-        InputStream trustInput = null;
+    private TrustManager[] getTrustManagerFactory(String truststoreFile, String storePass) throws IOException, GeneralSecurityException {
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+
+        InputStream is = null;
         try {
-            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
-            trustInput = new FileInputStream(truststoreFile);
-            trustStore.load(trustInput, storePass.toCharArray());
-            trustManagerFactory.init(trustStore);
-            return trustManagerFactory.getTrustManagers();
+            is = new FileInputStream(truststoreFile);
+
+            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+            ks.load(is, storePass.toCharArray());
+
+            tmf.init(ks);
+
+            return tmf.getTrustManagers();
         }
         finally {
             try {
-                if (trustInput != null)
-                    trustInput.close();
+                if (is != null) {
+                    is.close();
+                }
             }
             catch (IOException e) {
-                // TODO log
+                // Ignore; we're only reading from it...
             }
         }
     }
-
-    private static Types getType(String name) {
-        try {
-            return Types.valueOf(name.toUpperCase().trim());
-        }
-        catch (Exception e) {
-            return Types.NONE;
-        }
-    }
-
-    private static class UrlCredentials {
-
-        final static UrlCredentials EMPTY_CREDENTIALS = new UrlCredentials(Types.NONE, new Object[0]);
-        private final Types m_type;
-        private final Object[] m_credentials;
-
-        public UrlCredentials(Types type, Object... credentials) {
-            m_type = type;
-            m_credentials = (credentials == null) ? new Object[0] : credentials.clone();
-        }
-
-        public Object[] getCredentials() {
-            return m_credentials.clone();
-        }
-
-        public Types getType() {
-            return m_type;
-        }
-    }
 }

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionUtil.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionUtil.java?rev=1521521&r1=1521520&r2=1521521&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionUtil.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionUtil.java Tue Sep 10 15:14:46 2013
@@ -18,7 +18,10 @@
  */
 package org.apache.ace.agent.impl;
 
+import java.io.Closeable;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.URLConnection;
 
@@ -27,40 +30,95 @@ import org.apache.ace.agent.RetryAfterEx
 /**
  * Common utility functions for components that work with server connections.
  */
-public class ConnectionUtil {
+class ConnectionUtil {
+    /**
+     * The HTTP header indicating the 'backoff' time to use. See section 14.37 of HTTP1.1 spec (RFC2616).
+     */
+    private static final String HTTP_RETRY_AFTER = "Retry-After";
+    /**
+     * Default backoff time, in seconds.
+     */
+    private static final int DEFAULT_RETRY_TIME = 30;
+    /** Default buffer size for use in stream-copying, in bytes. */
+    private static final int DEFAULT_BUFFER_SIZE = 32 * 1024;
 
     /**
      * Check the server response code and throws exceptions if it is not 200.
      * 
-     * @param connection The connection to check
-     * @throws RetryAfterException If the server response is 503
-     * @throws IOException If the server response is other
+     * @param connection
+     *            The connection to check
+     * @throws RetryAfterException
+     *             If the server response is 503 indicating it is not (yet) available. The backoff time (= minimum time
+     *             to wait) is included in this exception;
+     * @throws IOException
+     *             If the server response is any other code than 200 or 503.
      */
     public static void checkConnectionResponse(URLConnection connection) throws RetryAfterException, IOException {
+        int responseCode = getResponseCode(connection);
+        switch (responseCode) {
+            case 200:
+                return;
+            case 503:
+                int retry = ((HttpURLConnection) connection).getHeaderFieldInt(HTTP_RETRY_AFTER, DEFAULT_RETRY_TIME);
+                throw new RetryAfterException(retry);
+            default:
+                throw new IOException("Unable to handle server responsecode: " + responseCode);
+        }
+    }
 
+    /**
+     * Closes a given URL connection, if necessary.
+     * 
+     * @param connection
+     *            the URL connection to close, can be <code>null</code> in which case this method does nothing.
+     */
+    public static void close(URLConnection connection) {
         if (connection instanceof HttpURLConnection) {
-            int responseCode = ((HttpURLConnection) connection).getResponseCode();
-            switch (responseCode) {
-                case 200:
-                    return;
-                case 503:
-                    int retry = 30;
-                    String header = ((HttpURLConnection) connection).getHeaderField("Retry-After");
-                    if (header != null) {
-                        try {
-                            retry = Integer.parseInt(header);
-                        }
-                        catch (NumberFormatException e) {
-                        }
-                    }
-                    throw new RetryAfterException(retry);
-                default:
-                    throw new IOException("Unable to handle server responsecode: " + responseCode);
+            ((HttpURLConnection) connection).disconnect();
+        }
+    }
+
+    public static void closeSilently(Closeable closeable) {
+        try {
+            if (closeable != null) {
+                closeable.close();
             }
         }
+        catch (IOException exception) {
+            // Ignore...
+        }
     }
 
-    private ConnectionUtil() {
+    public static void copy(InputStream is, OutputStream os) throws IOException {
+        copy(is, os, DEFAULT_BUFFER_SIZE);
+    }
+
+    public static void copy(InputStream is, OutputStream os, int bufferSize) throws IOException {
+        byte[] buffer = new byte[bufferSize];
 
+        int bytes;
+        while ((bytes = is.read(buffer)) != -1) {
+            os.write(buffer, 0, bytes);
+        }
+    }
+
+    /**
+     * Returns the response code for the given URL connection (assuming this connection represents a HTTP(S) URL).
+     * 
+     * @param connection
+     *            the URL connection to get the response code for, can be <code>null</code>.
+     * @return the response code for the given connection, or <code>-1</code> if it could not be determined.
+     * @throws IOException
+     *             if retrieving the response code failed.
+     */
+    public static int getResponseCode(URLConnection connection) throws IOException {
+        if (connection instanceof HttpURLConnection) {
+            return ((HttpURLConnection) connection).getResponseCode();
+        }
+        return -1;
+    }
+
+    private ConnectionUtil() {
+        // Nop
     }
 }



Mime
View raw message