You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by br...@apache.org on 2013/08/14 14:22:11 UTC

svn commit: r1513834 [1/2] - in /ace/sandbox/bramk/org.apache.ace.agent: ./ src/org/apache/ace/agent/ src/org/apache/ace/agent/configuration/ src/org/apache/ace/agent/connection/ src/org/apache/ace/agent/deployment/ src/org/apache/ace/agent/discovery/ ...

Author: bramk
Date: Wed Aug 14 12:22:10 2013
New Revision: 1513834

URL: http://svn.apache.org/r1513834
Log:
[sandbox] Agent impl wip; default connection implementation and test. Also simplified packages

Added:
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DeploymentHandler.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DiscoveryHandler.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandler.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadResult.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadState.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/IdentificationHandler.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/RetryAfterException.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DeploymentHandlerImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadHandleImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadHandlerImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadResultImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/IdentificationHandlerImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ConnectionHandlerImplTest.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DeploymentHandlerTest.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DiscoveryHandlerImplTest.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandlerTest.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/impl/IdentificationhandlerImplTest.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseAgentTest.java
Removed:
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/configuration/
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/connection/
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/discovery/
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/download/
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/identification/
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/deployment/
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/discovery/
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/download/
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/identification/
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseEasyMockTest.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/BaseWebServerTest.java
Modified:
    ace/sandbox/bramk/org.apache.ace.agent/bnd.bnd
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentControl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/FeedbackChannel.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContext.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java
    ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/impl/CustomControllerTest.java
    ace/sandbox/bramk/org.apache.ace.agent/test/org/apache/ace/agent/testutil/TestWebServer.java

Modified: ace/sandbox/bramk/org.apache.ace.agent/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/bnd.bnd?rev=1513834&r1=1513833&r2=1513834&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/bnd.bnd (original)
+++ ace/sandbox/bramk/org.apache.ace.agent/bnd.bnd Wed Aug 14 12:22:10 2013
@@ -3,13 +3,13 @@ Bundle-Description: Implementation of th
 Bundle-Version: 1.0.0
 Bundle-Activator: org.apache.ace.agent.impl.Activator
 
-Private-Package: org.apache.ace.agent.connection.impl,\
-	org.apache.ace.agent.configuration.impl,\
-	org.apache.ace.agent.identification.impl,\
-	org.apache.ace.agent.discovery.impl,\
-	org.apache.ace.agent.deployment.impl,\
-	org.apache.ace.agent.download.impl,\
+Private-Package: \
 	org.apache.ace.agent.impl,\
+    org.apache.commons.codec,\
+	org.apache.commons.codec.binary,\
+	org.apache.commons.codec.digest,\
+	org.apache.commons.codec.language,\
+	org.apache.commons.codec.net,\
 	org.apache.felix.deploymentadmin,\
 	org.apache.felix.deploymentadmin.spi,\
 	org.apache.felix.dm.impl.dependencies,\
@@ -27,15 +27,10 @@ Import-Package: \
 	org.osgi.service.log;resolution:=optional,\
 	*
 	
-Export-Package: org.apache.ace.agent,\
-	org.apache.ace.agent.download,\
-	org.apache.ace.agent.deployment,\
+Export-Package: \
+    org.apache.ace.agent,\
 	org.osgi.service.deploymentadmin;-split-package:=merge-last,\
-	org.osgi.service.deploymentadmin.spi;-split-package:=merge-last,\
-	org.apache.ace.agent.discovery,\
-	org.apache.ace.agent.identification,\
-	org.apache.ace.agent.connection,\
-	org.apache.ace.agent.configuration
+	org.osgi.service.deploymentadmin.spi;-split-package:=merge-last
 
 -buildpath: osgi.core;version=4.2,\
 	osgi.cmpn;version=4.2,\
@@ -50,7 +45,8 @@ Export-Package: org.apache.ace.agent,\
 	org.eclipse.jetty.continuation;version=7.6.9.v20130131,\
 	org.apache.felix.deploymentadmin;version=0.9.4,\
 	org.easymock,\
-	org.apache.felix.dependencymanager
+	org.apache.felix.dependencymanager,\
+	org.apache.commons.codec
 
 -sources false
 -runfw: org.apache.felix.framework;version='[4.0.3,4.0.3]'

Modified: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java?rev=1513834&r1=1513833&r2=1513834&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java (original)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentConstants.java Wed Aug 14 12:22:10 2013
@@ -1,6 +1,31 @@
+/*
+ * 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;
 
+/**
+ * Compile time constants for this package.
+ * 
+ */
 public interface AgentConstants {
 
+    /**
+     * HTTP headers name for Deployment Package size estimate.
+     */
     String HEADER_DPSIZE = "X-ACE-DPSize";
 }

Modified: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentControl.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentControl.java?rev=1513834&r1=1513833&r2=1513834&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentControl.java (original)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/AgentControl.java Wed Aug 14 12:22:10 2013
@@ -1,10 +1,25 @@
+/*
+ * 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.List;
 
-import org.apache.ace.agent.configuration.ConfigurationHandler;
-import org.apache.ace.agent.deployment.DeploymentHandler;
-import org.apache.ace.agent.download.DownloadHandler;
 
 /**
  * The agent's control (service) interface. Provides control functions and access to configuration for consumers that

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConfigurationHandler.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,119 @@
+/*
+ * 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;
+import java.util.logging.Level;
+
+/**
+ * The agent's persisted configuration. External launchers can override the default values through system properties
+ * when the agent starts. However, once a configuration value has been stored in the persisted configuration is will no
+ * longer be overwritten by system properties. This ensures a simple system restart will not override configuration set
+ * by runtime controllers.
+ */
+// TODO should we support recovery by allow config overrides through system properties or should a luancher just wip
+// the bundle cache when it requires a clean boostrap?
+public interface ConfigurationHandler {
+
+    // NOTE Configuration of the default subsystems for identification, discovery and connection handling is not part of
+    // this definition. Even though they are default implementations the are still extensions.
+
+    /**
+     * Sync interval; When sync is active it will automatically install updates and send feedback to the server. The
+     * time unit is seconds. A value of 0 or less disables the sync.
+     */
+    String CONFIG_KEY_SYNC_INTERVAL = ConfigurationHandler.class.getPackage().getName() + ".syncinterval";
+    long CONFIG_DEFAULT_SYNC_INTERVAL = 300l;
+
+    void setSyncInterval(long seconds);
+
+    long getSyncInterval();
+
+    /**
+     * SyncRetries value; When an install fails during a sync the agent can try to recover by ignoring optimization
+     * flags and potentially restarting a Deployment Package download. A value of 1 or less disables the retry behavior.
+     */
+    String CONFIG_KEY_SYNC_RETRIES = ConfigurationHandler.class.getPackage().getName() + ".syncretries";
+    int CONFIG_DEFAULT_SYNC_RETRIES = 3;
+
+    void setSyncRetries(int value);
+
+    int getSyncRetries();
+
+    /**
+     * UpdateStreaming flag; When set Deployment Packages are installed directly from the download stream reducing
+     * overhead and disk usage, but disabling resume capabilities. This strategy is of interest to highly resource
+     * constraint devices and/or system with highly reliable connectivity and no need for resume semantics.
+     */
+    String CONFIG_KEY_STREAMING_UPDATES = ConfigurationHandler.class.getPackage().getName() + ".updatestreaming";
+    boolean CONFIG_DEFAULT_UPDATE_STREAMING = false;
+
+    void setUpdateStreaming(boolean flag);
+
+    boolean getUpdateStreaming();
+
+    /**
+     * StopUnaffected flag; When set all target bundles of a Deployment Package will be restarted as part of the
+     * deployment session. Otherwise the agent tries to minimize the impact by only restarting bundles that are actually
+     * affected. Not stopping unaffected bundles reduces overhead, but may fail in complex wiring scenarios.
+     */
+    String CONFIG_KEY_STOP_UNAFFECTED = ConfigurationHandler.class.getPackage().getName() + ".stopunaffected";
+    boolean CONFIG_DEFAULT_STOP_UNAFFECTED = true; // spec behavior
+
+    void setStopUnaffected(boolean flag);
+
+    boolean getStopUnaffected();
+
+    /**
+     * FixPackages flag; When set the Agent will request the server for fix packages instead of full deployment
+     * packages. This behavior significantly reduces bandwidth consumption.
+     */
+    String CONFIG_KEY_FIX_PACKAGES = ConfigurationHandler.class.getPackage().getName() + ".fixpackages";
+    boolean CONFIG_DEFAULT_FIX_PACKAGES = true;
+
+    void setFixPackage(boolean flag);
+
+    boolean getFixPackages();
+
+    /**
+     * Log level; Logging uses standard Java logging to guarantee optimal compatibility in any standard Java
+     * environment.
+     */
+    String CONFIG_KEY_LOG_LEVEL = ConfigurationHandler.class.getPackage().getName() + ".loglevel";
+    Level CONFIG_DEFAULT_LOG_LEVEL = Level.INFO;
+
+    void setLogLevel(Level level);
+
+    Level getLogLevel();
+
+    /**
+     * Custom configuration keys; This is provided to allow a launcher to specify system properties that should be
+     * included in the persistent configuration map. The initial values of these properties are only read once when the
+     * agent starts and only stored if no value is set in the configuration map.
+     */
+    String CONFIG_KEY_EXTENSION_PROPERTIES = ConfigurationHandler.class.getPackage().getName() + ".extensionkeys";
+
+    /**
+     * Direct access to the configuration map; This is provided to allow extensions to access custom configuration
+     * properties.
+     */
+    void setMap(Map<String, String> configuration);
+
+    Map<String, String> getMap();
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/ConnectionHandler.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,39 @@
+/*
+ * 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.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+/**
+ * Agent control delegate interface that is responsible for opening connection.
+ * 
+ */
+public interface ConnectionHandler {
+
+    /**
+     * Return a connection for the specified url.
+     * 
+     * @param url The URL
+     * @return The connection
+     * @throws IOException If opening the connection fails
+     */
+    URLConnection getConnection(URL url) throws IOException;
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DeploymentHandler.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DeploymentHandler.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DeploymentHandler.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DeploymentHandler.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,88 @@
+/*
+ * 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.io.IOException;
+import java.io.InputStream;
+import java.util.SortedSet;
+
+import org.osgi.framework.Version;
+
+/**
+ * Agent control delegate interface that provides the deployment functions.
+ * 
+ */
+public interface DeploymentHandler {
+
+    /**
+     * Return the installed deployment package version for this agent.
+     * 
+     * @return The installed version, {@link Version.emptyVersion} if no packages have been installed
+     */
+    Version getInstalledVersion();
+
+    /**
+     * Return the sorted set of available deployment package versions as reported by the server.
+     * 
+     * @return The sorted set of versions, may be empty
+     * @throws RetryAfterException If the server indicates it is too busy with a Retry-After header
+     * @throws IOException If the connection to the server fails
+     */
+    SortedSet<Version> getAvailableVersions() throws RetryAfterException, IOException;
+
+    /**
+     * Return the estimated size for a deployment package as reported by the server.
+     * 
+     * @param version The version of the package
+     * @param fixPackage Request the server for a fix-package
+     * @return The estimated size in bytes, <code>-1</code> indicates the size is unknown
+     * @throws RetryAfterException If the server indicates it is too busy with a Retry-After header
+     * @throws IOException If the connection to the server fails
+     */
+    long getPackageSize(Version version, boolean fixPackage) throws RetryAfterException, IOException;
+
+    /**
+     * Returns the {@link InputStream} for a deployment package.
+     * 
+     * @param version The version of the deployment package
+     * @param fixPackage Request the server for a fix-package
+     * @return The input-stream for the deployment package
+     * @throws RetryAfterException If the server indicates it is too busy with a Retry-After header
+     * @throws IOException If the connection to the server fails
+     */
+    InputStream getInputStream(Version version, boolean fixPackage) throws RetryAfterException, IOException;
+
+    /**
+     * Return the {@link DownloadHandle} for a deployment package.
+     * 
+     * @param version The version of the deployment package
+     * @param fixPackage Request the server for a fix-package
+     * @return The download handle
+     */
+    DownloadHandle getDownloadHandle(Version version, boolean fixPackage);
+
+    /**
+     * Install a deployment package from an input stream.
+     * 
+     * @param inputStream The inputStream, not <code>null</code>
+     * @throws IOException If reading the input stream fails.
+     */
+    // TODO deployment exceptions
+    void deployPackage(InputStream inputStream) throws IOException;
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DiscoveryHandler.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DiscoveryHandler.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DiscoveryHandler.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DiscoveryHandler.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,36 @@
+/*
+ * 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.net.URL;
+
+/**
+ * Agent control delegate interface that is responsible for discovering servers. If the handler supports dynamic
+ * discovery or multiple URLs it should select the most appropriate candidate.
+ * 
+ */
+public interface DiscoveryHandler {
+
+    /**
+     * Return a server base URL.
+     * 
+     * @return The URL, <code>null</code> if none is available
+     */
+    URL getServerUrl();
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,108 @@
+/*
+ * 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;
+
+/**
+ * A {@link DownloadHandle} provides control over an asynchronous download and access to the resulting file when the it
+ * is completed. <br/>
+ * <br/>
+ * Consumers must consider the following rules;
+ * <ul>
+ * <li>Control methods must be called in logical order.
+ * <li>Implementations are not expected to be thread-safe.
+ * <li>Resulting files must be assumed to be transient.
+ * <ul>
+ */
+public interface DownloadHandle {
+
+    /**
+     * Size of the buffer used while downloading the content stream.
+     */
+    int DEFAULT_READBUFFER_SIZE = 1024;
+
+    /**
+     * Callback interface; when registered the progress method will be invoked while downloading the content stream for
+     * every {@link READBUFFER_SIZE} bytes.
+     */
+    interface ProgressListener {
+        /**
+         * Called while downloading the content stream.
+         * 
+         * @param contentLength The total length of the content or -1 if unknown.
+         * @param progress The number of bytes that has been received so far.
+         */
+        void progress(long contentLength, long progress);
+    }
+
+    /**
+     * Callback interface; when registered the completed method will be invoked when the download terminates for any
+     * reason.
+     * 
+     */
+    interface CompletedListener {
+        /**
+         * Called when a download terminates.
+         * 
+         * @param result The result of the download.
+         */
+        void completed(DownloadResult result);
+    }
+
+    /**
+     * Registers the progress listener.
+     * 
+     * @param listener The progress listener.
+     * @return this
+     */
+    DownloadHandle setProgressListener(ProgressListener listener);
+
+    /**
+     * Registers the completion listener.
+     * 
+     * @param listener The completion listener.
+     * @return this
+     */
+    DownloadHandle setCompletionListener(CompletedListener listener);
+
+    /**
+     * Starts the download.
+     * 
+     * @return this
+     */
+    DownloadHandle start();
+
+    /**
+     * Pauses the download.
+     * 
+     * @return this
+     */
+    DownloadHandle stop();
+
+    /**
+     * Retrieves the download result. Will wait for completion before returning.
+     * 
+     * @return The result of the download
+     */
+    DownloadResult result();
+
+    /**
+     * Releases any resources that may be held by the handle.
+     */
+    void discard();
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandler.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandler.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandler.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandler.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.agent;
+
+import java.net.URL;
+
+/**
+ * Service interface for a DownloadHandler component.
+ */
+public interface DownloadHandler {
+
+    /**
+     * Returns a {@link DownloadHandle} for a URL.
+     * 
+     * @param url The url
+     * @return The {@link DownloadHandle}
+     */
+    DownloadHandle getHandle(URL url);
+    
+    //TODO named handlers (resume over urls)
+    DownloadHandle getHandle(URL url, int readBufferSize);
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadResult.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadResult.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadResult.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadResult.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,55 @@
+/*
+ * 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.io.File;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents the result of a download task.
+ * 
+ */
+public interface DownloadResult {
+
+    /**
+     * Returns the state of the result.
+     * 
+     * @return The state
+     */
+    DownloadState getState();
+
+    /**
+     * Returns the download file.
+     * 
+     * @return The file, <code>null</code> if the download was unsuccessful
+     */
+    //TODO inputstream
+    File getFile();
+
+    int getCode();
+    
+    Map<String, List<String>> getHeaders();
+    /**
+     * Return the cause of an unsuccessful download.
+     * 
+     * @return The cause, <code>null</code> if the download was successful
+     */
+    Throwable getCause();
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadState.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadState.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadState.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadState.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+/**
+ * The state of a download handle that completed.
+ */
+public enum DownloadState {
+    /**
+     * The handle completed successfully.
+     */
+    SUCCESSFUL,
+    /**
+     * The handle completed because it was stopped.
+     */
+    STOPPED,
+    /**
+     * The handle completed due to an unrecoverable error. It can not be resumed.
+     */
+    FAILED,
+}

Modified: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/FeedbackChannel.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/FeedbackChannel.java?rev=1513834&r1=1513833&r2=1513834&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/FeedbackChannel.java (original)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/FeedbackChannel.java Wed Aug 14 12:22:10 2013
@@ -1,10 +1,31 @@
+/*
+ * 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.io.IOException;
 import java.util.Map;
 
-import org.apache.ace.agent.deployment.RetryAfterException;
 
+/**
+ * 
+ *
+ */
 public interface FeedbackChannel {
 
     /**

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/IdentificationHandler.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/IdentificationHandler.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/IdentificationHandler.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/IdentificationHandler.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * Agent control delegate interface that is responsible for target identification.
+ * 
+ */
+public interface IdentificationHandler {
+
+    /**
+     * Return the agent identification.
+     * 
+     * @return The identification, <code>null</code> if none is available.
+     */
+    String getIdentification();
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/RetryAfterException.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/RetryAfterException.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/RetryAfterException.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/RetryAfterException.java Wed Aug 14 12:22:10 2013
@@ -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;
+
+public class RetryAfterException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+    private final int m_seconds;
+
+    public RetryAfterException(int seconds) {
+        super("Server too busy. Retry after " + seconds + " seconds");
+        m_seconds = seconds;
+    }
+    
+    public int getSeconds(){
+        return m_seconds;
+    }
+}

Modified: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java?rev=1513834&r1=1513833&r2=1513834&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java (original)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java Wed Aug 14 12:22:10 2013
@@ -1,21 +1,33 @@
+/*
+ * 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.impl;
 
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 
 import org.apache.ace.agent.AgentControl;
-import org.apache.ace.agent.configuration.ConfigurationHandler;
-import org.apache.ace.agent.configuration.impl.ConfigurationHandlerImpl;
-import org.apache.ace.agent.connection.ConnectionHandler;
-import org.apache.ace.agent.connection.impl.ConnectionHandlerImpl;
-import org.apache.ace.agent.deployment.DeploymentHandler;
-import org.apache.ace.agent.deployment.impl.DeploymentHandlerImpl;
-import org.apache.ace.agent.discovery.DiscoveryHandler;
-import org.apache.ace.agent.discovery.impl.DiscoveryHandlerImpl;
-import org.apache.ace.agent.download.DownloadHandler;
-import org.apache.ace.agent.download.impl.DownloadHandlerImpl;
-import org.apache.ace.agent.identification.IdentificationHandler;
-import org.apache.ace.agent.identification.impl.IdentificationHandlerImpl;
+import org.apache.ace.agent.ConfigurationHandler;
+import org.apache.ace.agent.ConnectionHandler;
+import org.apache.ace.agent.DeploymentHandler;
+import org.apache.ace.agent.DiscoveryHandler;
+import org.apache.ace.agent.DownloadHandler;
+import org.apache.ace.agent.IdentificationHandler;
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyActivatorBase;
 import org.apache.felix.dm.DependencyManager;
@@ -124,7 +136,7 @@ public class Activator extends Dependenc
     }
 
     @Override
-    public ConfigurationHandler getConfiguration() {
+    public ConfigurationHandler getConfigurationHandler() {
         return m_configurationHandler;
     }
 

Modified: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContext.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContext.java?rev=1513834&r1=1513833&r2=1513834&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContext.java (original)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentContext.java Wed Aug 14 12:22:10 2013
@@ -1,13 +1,31 @@
+/*
+ * 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.impl;
 
 import java.util.concurrent.ScheduledExecutorService;
 
-import org.apache.ace.agent.configuration.ConfigurationHandler;
-import org.apache.ace.agent.connection.ConnectionHandler;
-import org.apache.ace.agent.deployment.DeploymentHandler;
-import org.apache.ace.agent.discovery.DiscoveryHandler;
-import org.apache.ace.agent.download.DownloadHandler;
-import org.apache.ace.agent.identification.IdentificationHandler;
+import org.apache.ace.agent.ConfigurationHandler;
+import org.apache.ace.agent.ConnectionHandler;
+import org.apache.ace.agent.DeploymentHandler;
+import org.apache.ace.agent.DiscoveryHandler;
+import org.apache.ace.agent.DownloadHandler;
+import org.apache.ace.agent.IdentificationHandler;
 
 public interface AgentContext {
 
@@ -23,5 +41,5 @@ public interface AgentContext {
     
     ScheduledExecutorService getExecutorService();
     
-    ConfigurationHandler getConfiguration();
+    ConfigurationHandler getConfigurationHandler();
 }

Modified: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java?rev=1513834&r1=1513833&r2=1513834&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java (original)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/AgentControlImpl.java Wed Aug 14 12:22:10 2013
@@ -1,12 +1,30 @@
+/*
+ * 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.impl;
 
 import java.util.List;
 
 import org.apache.ace.agent.AgentControl;
+import org.apache.ace.agent.ConfigurationHandler;
+import org.apache.ace.agent.DeploymentHandler;
+import org.apache.ace.agent.DownloadHandler;
 import org.apache.ace.agent.FeedbackChannel;
-import org.apache.ace.agent.configuration.ConfigurationHandler;
-import org.apache.ace.agent.deployment.DeploymentHandler;
-import org.apache.ace.agent.download.DownloadHandler;
 
 public class AgentControlImpl implements AgentControl {
 
@@ -18,7 +36,7 @@ public class AgentControlImpl implements
 
     @Override
     public ConfigurationHandler getConfiguration() {
-        return m_agentContext.getConfiguration();
+        return m_agentContext.getConfigurationHandler();
     }
 
     @Override

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConfigurationHandlerImpl.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,97 @@
+/*
+ * 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.impl;
+
+import java.util.Map;
+import java.util.logging.Level;
+
+import org.apache.ace.agent.ConfigurationHandler;
+
+public class ConfigurationHandlerImpl implements ConfigurationHandler {
+
+    private final AgentContext m_agentContext;
+
+    public ConfigurationHandlerImpl(AgentContext agentContext) {
+        m_agentContext = agentContext;
+    }
+
+    @Override
+    public void setSyncInterval(long seconds) {
+    }
+
+    @Override
+    public long getSyncInterval() {
+        return 10;
+    }
+
+    @Override
+    public void setSyncRetries(int value) {
+    }
+
+    @Override
+    public int getSyncRetries() {
+        return 3;
+    }
+
+    @Override
+    public void setUpdateStreaming(boolean flag) {
+    }
+
+    @Override
+    public boolean getUpdateStreaming() {
+        return false;
+    }
+
+    @Override
+    public void setStopUnaffected(boolean flag) {
+    }
+
+    @Override
+    public boolean getStopUnaffected() {
+        return false;
+    }
+
+    @Override
+    public void setFixPackage(boolean flag) {
+    }
+
+    @Override
+    public boolean getFixPackages() {
+        return false;
+    }
+
+    @Override
+    public void setLogLevel(Level level) {
+    }
+
+    @Override
+    public Level getLogLevel() {
+        return null;
+    }
+
+    @Override
+    public void setMap(Map<String, String> configuration) {
+    }
+
+    @Override
+    public Map<String, String> getMap() {
+        return null;
+    }
+
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ConnectionHandlerImpl.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,233 @@
+/*
+ * 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.impl;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.apache.ace.agent.ConnectionHandler;
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * Default connection handler with support for BASIC authentication and HTTPS client certificates.
+ * 
+ */
+public class ConnectionHandlerImpl implements ConnectionHandler {
+
+    public static final String PROP_AUTHTYPE = "agent.authType";
+    public static final String PROP_AUTHUSER = "agent.authUser";
+    public static final String PROP_AUTHPASS = "agent.authPass";
+    public static final String PROP_AUTHKEYFILE = "agent.authKeyFile";
+    public static final String PROP_AUTHKEYPASS = "agent.authKeyPass";
+    public static final String PROP_AUTHTRUSTFILE = "agent.authTrustFile";
+    public static final String PROP_AUTHTRUSTPASS = "agent.authTrustPass";
+
+    private static final String HTTP_HEADER_AUTHORIZATION = "Authorization";
+
+    private enum AuthType {
+
+        NONE,
+        BASIC,
+        CLIENT_CERT;
+
+        static AuthType getAuthType(String name) {
+            if (name.equals(NONE.name()))
+                return NONE;
+            if (name.equals(BASIC.name()))
+                return BASIC;
+            if (name.equals(CLIENT_CERT.name()))
+                return CLIENT_CERT;
+            return null;
+        }
+    }
+
+    private static class UrlCredentials {
+
+        final static UrlCredentials EMPTY_CREDENTIALS = new UrlCredentials(AuthType.NONE, new Object[0]);
+
+        private final AuthType m_type;
+        private final Object[] m_credentials;
+
+        public UrlCredentials(AuthType type, Object... credentials) {
+            m_type = type;
+            m_credentials = (credentials == null) ? new Object[0] : credentials.clone();
+        }
+
+        public Object[] getCredentials() {
+            return m_credentials.clone();
+        }
+
+        public AuthType getType() {
+            return m_type;
+        }
+    }
+
+    private final AgentContext m_agentContext;
+
+    public ConnectionHandlerImpl(AgentContext agentContext) {
+        m_agentContext = agentContext;
+    }
+
+    @Override
+    public URLConnection getConnection(URL url) throws IOException {
+        URLConnection connection = (HttpURLConnection) url.openConnection();
+        UrlCredentials credentials = getCredentials();
+        if (credentials != null) {
+            if (credentials != null && credentials.getType() == AuthType.BASIC)
+                applyBasicAuthentication(connection, credentials.getCredentials());
+
+            else if (credentials != null && credentials.getType() == AuthType.CLIENT_CERT) {
+                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!");
+        }
+
+        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]));
+        }
+
+        return "Basic " + new String(Base64.encodeBase64(sb.toString().getBytes()));
+    }
+
+    private void applyBasicAuthentication(URLConnection conn, Object[] values) {
+        if (conn instanceof HttpURLConnection) {
+            conn.setRequestProperty(HTTP_HEADER_AUTHORIZATION, getBasicAuthCredentials(values));
+        }
+    }
+
+    private void applyClientCertificate(URLConnection conn, Object[] values) {
+        if (conn instanceof HttpsURLConnection) {
+            ((HttpsURLConnection) conn).setSSLSocketFactory(((SSLContext) values[0]).getSocketFactory());
+        }
+    }
+
+    public UrlCredentials getCredentials() {
+
+        String configValue = getConfigurationValue(PROP_AUTHTYPE);
+        AuthType authType = AuthType.getAuthType(configValue == null ? "" : configValue.trim().toUpperCase());
+        if (authType == null || authType == AuthType.NONE) {
+            return UrlCredentials.EMPTY_CREDENTIALS;
+        }
+
+        if (authType == AuthType.BASIC) {
+            String username = getConfigurationValue(PROP_AUTHUSER);
+            String password = getConfigurationValue(PROP_AUTHPASS);
+            return new UrlCredentials(AuthType.BASIC,
+                new Object[] { username == null ? "" : username, password == null ? "" : password });
+        }
+
+        if (authType == AuthType.CLIENT_CERT) {
+            String keystoreFile = getConfigurationValue(PROP_AUTHKEYFILE);
+            String keystorePass = getConfigurationValue(PROP_AUTHKEYPASS);
+            String truststoreFile = getConfigurationValue(PROP_AUTHTRUSTFILE);
+            String truststorePass = getConfigurationValue(PROP_AUTHTRUSTPASS);
+
+            // 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(AuthType.CLIENT_CERT,
+                    new Object[] { context });
+            }
+            catch (Exception e) {
+                // TODO log
+            }
+        }
+        return null;
+    }
+
+    private String getConfigurationValue(String key) {
+        return m_agentContext.getConfigurationHandler().getMap().get(key);
+    }
+
+    private static KeyManager[] getKeyManagerFactory(String keystoreFile, String storePass) throws IOException, GeneralSecurityException {
+        InputStream keyInput = 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();
+        }
+        finally {
+            try {
+                if (keyInput != null)
+                    keyInput.close();
+            }
+            catch (IOException e) {
+                // TODO log
+            }
+        }
+    }
+
+    private static TrustManager[] getTrustManagerFactory(String truststoreFile, String storePass) throws IOException, GeneralSecurityException {
+        InputStream trustInput = 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();
+        }
+        finally {
+            try {
+                if (trustInput != null)
+                    trustInput.close();
+            }
+            catch (IOException e) {
+                // TODO log
+            }
+        }
+    }
+}

Modified: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java?rev=1513834&r1=1513833&r2=1513834&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java (original)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java Wed Aug 14 12:22:10 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.impl;
 
 import java.io.IOException;
@@ -8,11 +26,15 @@ import java.util.concurrent.ScheduledFut
 import java.util.concurrent.TimeUnit;
 
 import org.apache.ace.agent.AgentControl;
-import org.apache.ace.agent.configuration.ConfigurationHandler;
-import org.apache.ace.agent.deployment.DeploymentHandler;
-import org.apache.ace.agent.deployment.RetryAfterException;
+import org.apache.ace.agent.ConfigurationHandler;
+import org.apache.ace.agent.DeploymentHandler;
+import org.apache.ace.agent.RetryAfterException;
 import org.osgi.framework.Version;
 
+/**
+ * Default configurable controller
+ * 
+ */
 public class DefaultController implements Runnable {
 
     private final AgentControl m_agentControl;

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DeploymentHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DeploymentHandlerImpl.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DeploymentHandlerImpl.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DeploymentHandlerImpl.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,229 @@
+/*
+ * 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.impl;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.ace.agent.AgentConstants;
+import org.apache.ace.agent.DeploymentHandler;
+import org.apache.ace.agent.DownloadHandle;
+import org.apache.ace.agent.RetryAfterException;
+import org.apache.felix.deploymentadmin.DeploymentAdminImpl;
+import org.osgi.framework.Version;
+import org.osgi.service.deploymentadmin.DeploymentAdmin;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.deploymentadmin.DeploymentPackage;
+
+public class DeploymentHandlerImpl implements DeploymentHandler {
+
+    private final AgentContext m_agentContext;
+    private DeploymentAdmin m_deploymentAdmin;
+
+    public DeploymentHandlerImpl(AgentContext agentContext) {
+        this(agentContext, new DeploymentAdminImpl());
+    }
+
+    public DeploymentHandlerImpl(AgentContext agentContext, DeploymentAdmin deploymentAdmin) {
+        m_agentContext = agentContext;
+        m_deploymentAdmin = deploymentAdmin;
+    }
+
+    @Override
+    public Version getInstalledVersion() {
+        Version highestVersion = Version.emptyVersion;
+        DeploymentPackage[] installedPackages = m_deploymentAdmin.listDeploymentPackages();
+        for (DeploymentPackage installedPackage : installedPackages) {
+            if (installedPackage.getName().equals(getIdentification())
+                && installedPackage.getVersion().compareTo(highestVersion) > 0) {
+                highestVersion = installedPackage.getVersion();
+            }
+        }
+        return highestVersion;
+    }
+
+    @Override
+    public SortedSet<Version> getAvailableVersions() throws RetryAfterException, IOException {
+
+        SortedSet<Version> versions = new TreeSet<Version>();
+
+        URL endpoint = getEndpoint(getServerURL(), getIdentification());
+        URLConnection connection = null;
+        BufferedReader reader = null;
+        try {
+            connection = getConnection(endpoint);
+
+            // TODO handle problems and retries
+            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+            String versionString;
+            while ((versionString = reader.readLine()) != null) {
+                try {
+                    Version version = Version.parseVersion(versionString);
+                    versions.add(version);
+                }
+                catch (IllegalArgumentException e) {
+                    throw new IOException(e);
+                }
+            }
+            return versions;
+        }
+        finally {
+            if (connection != null && connection instanceof HttpURLConnection)
+                ((HttpURLConnection) connection).disconnect();
+            if (reader != null)
+                reader.close();
+        }
+    }
+
+    @Override
+    public long getPackageSize(Version version, boolean fixPackage) throws RetryAfterException, IOException {
+
+        URL url = getPackageURL(version, fixPackage);
+        long packageSize = -1l;
+
+        URLConnection urlConnection = null;
+        InputStream inputStream = null;
+        try {
+            urlConnection = url.openConnection();
+            if (urlConnection instanceof HttpURLConnection)
+                ((HttpURLConnection) urlConnection).setRequestMethod("HEAD");
+
+            String dpSizeHeader = urlConnection.getHeaderField(AgentConstants.HEADER_DPSIZE);
+            if (dpSizeHeader != null)
+                try {
+                    packageSize = Long.parseLong(dpSizeHeader);
+                }
+                catch (NumberFormatException e) {
+                    // ignore
+                }
+            return packageSize;
+        }
+        finally {
+            if (urlConnection != null && urlConnection instanceof HttpURLConnection)
+                ((HttpURLConnection) urlConnection).disconnect();
+            if (inputStream != null)
+                try {
+                    inputStream.close();
+                }
+                catch (IOException e) {
+                    // ignore
+                }
+        }
+    }
+
+    @Override
+    public InputStream getInputStream(Version version, boolean fixPackage) throws RetryAfterException, IOException {
+        URL packageURL = getPackageURL(version, fixPackage);
+        URLConnection urlConnection = null;
+        InputStream inputStream = null;
+        try {
+            // TODO handle problems and retries
+            urlConnection = packageURL.openConnection();
+            inputStream = urlConnection.getInputStream();
+            return inputStream;
+        }
+        finally {
+            if (urlConnection != null && urlConnection instanceof HttpURLConnection)
+                ((HttpURLConnection) urlConnection).disconnect();
+            if (inputStream != null)
+                try {
+                    inputStream.close();
+                }
+                catch (IOException e) {
+                    e.printStackTrace();
+                }
+        }
+    }
+
+    @Override
+    public DownloadHandle getDownloadHandle(Version version, boolean fixPackage) {
+        URL packageURL = getPackageURL(version, fixPackage);
+        DownloadHandle downloadHandle = m_agentContext.getDownloadHandler().getHandle(packageURL);
+        return downloadHandle;
+    }
+
+    @Override
+    public void deployPackage(InputStream inputStream) {
+        // FIXME exceptions
+        try {
+            m_deploymentAdmin.installDeploymentPackage(inputStream);
+        }
+        catch (DeploymentException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private URL getPackageURL(Version version, boolean fixPackage) {
+        URL url = null;
+        if (fixPackage) {
+            url = getEndpoint(getServerURL(), getIdentification(), getInstalledVersion(), version);
+        }
+        else {
+            url = getEndpoint(getServerURL(), getIdentification(), version);
+        }
+        return url;
+    }
+
+    private String getIdentification() {
+        return m_agentContext.getIdentificationHandler().getIdentification();
+    }
+
+    private URL getServerURL() {
+        return m_agentContext.getDiscoveryHandler().getServerUrl();
+    }
+
+    private URLConnection getConnection(URL url) throws IOException {
+        return m_agentContext.getConnectionHandler().getConnection(url);
+    }
+
+    private static URL getEndpoint(URL serverURL, String identification) {
+        try {
+            return new URL(serverURL, "deployment/" + identification + "/versions/");
+        }
+        catch (MalformedURLException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    private URL getEndpoint(URL serverURL, String identification, Version version) {
+        try {
+            return new URL(serverURL, "deployment/" + identification + "/versions/" + version.toString());
+        }
+        catch (MalformedURLException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    private URL getEndpoint(URL serverURL, String identification, Version from, Version to) {
+        try {
+            return new URL(serverURL, "deployment/" + identification + "/versions/" + to.toString() + "?current=" + from);
+        }
+        catch (MalformedURLException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,109 @@
+/*
+ * 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.impl;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ace.agent.DiscoveryHandler;
+
+/**
+ * Default discovery handler that reads the serverURL(s) from the configuration using key {@link DISCOVERY_CONFIG_KEY}.
+ * 
+ */
+public class DiscoveryHandlerImpl implements DiscoveryHandler {
+
+    /**
+     * Configuration key for the default discovery handler. The value must be a comma-separated list of valid base
+     * server URLs.
+     */
+    // TODO move to and validate in config handler?
+    public static final String DISCOVERY_CONFIG_KEY = "agent.discovery";
+
+    private final AgentContext m_agentContext;
+
+    public DiscoveryHandlerImpl(AgentContext agentContext) throws Exception {
+        m_agentContext = agentContext;
+    }
+
+    // TODO Pretty naive implementation below. It always takes the first configurred URL it can connect to and is not
+    // thread-safe.
+    @Override
+    public URL getServerUrl() {
+        String configValue = m_agentContext.getConfigurationHandler().getMap().get(DISCOVERY_CONFIG_KEY);
+        if (configValue == null || configValue.equals(""))
+            return null;
+        if (configValue.indexOf(",") == -1) {
+            return checkURL(configValue.trim());
+        }
+        for (String configValuePart : configValue.split(",")) {
+            URL url = checkURL(configValuePart.trim());
+            if (url != null)
+                return url;
+        }
+        return null;
+    }
+
+    private static final long CACHE_TIME = 1000;
+
+    private static class CheckedURL {
+        URL url;
+        long timestamp;
+
+        public CheckedURL(URL url, long timestamp) {
+            this.url = url;
+            this.timestamp = timestamp;
+        }
+    }
+
+    private final Map<String, CheckedURL> m_checkedURLs = new HashMap<String, DiscoveryHandlerImpl.CheckedURL>();
+
+    private URL checkURL(String serverURL) {
+        CheckedURL checked = m_checkedURLs.get(serverURL);
+        if (checked != null && checked.timestamp > (System.currentTimeMillis() - CACHE_TIME)) {
+            return checked.url;
+        }
+        try {
+            URL url = new URL(serverURL);
+            tryConnect(url);
+            m_checkedURLs.put(serverURL, new CheckedURL(url, System.currentTimeMillis()));
+            return url;
+        }
+        catch (IOException e) {
+            // TODO log
+            return null;
+        }
+    }
+
+    private void tryConnect(URL serverURL) throws IOException {
+        URLConnection connection = null;
+        try {
+            connection = m_agentContext.getConnectionHandler().getConnection(serverURL);
+            connection.connect();
+        }
+        finally {
+            if (connection != null && connection instanceof HttpURLConnection)
+                ((HttpURLConnection) connection).disconnect();
+        }
+    }
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,194 @@
+/*
+ * 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.impl;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+class DownloadCallableImpl implements Callable<Void> {
+
+    // test support
+    static final int FAIL_OPENCONNECTION = 1;
+    static final int FAIL_OPENINPUTSTREAM = 2;
+    static final int FAIL_OPENOUTPUTSTREAM = 3;
+    static final int FAIL_AFTERFIRSTWRITE = 4;
+
+    private final DownloadHandleImpl m_handle;
+    private final URL m_source;
+    private final File m_target;
+    private final int m_readBufferSize;
+    private final int m_failAtPosition;
+
+    private volatile boolean m_abort = false;
+
+    DownloadCallableImpl(DownloadHandleImpl handle, URL source, File target, int readBufferSize, int failAtPosition) {
+        m_handle = handle;
+        m_source = source;
+        m_target = target;
+        m_readBufferSize = readBufferSize;
+        m_failAtPosition = failAtPosition;
+    }
+
+    @Override
+    public Void call() throws Exception {
+        return download();
+    }
+
+    /**
+     * Abort the download. Used instead of a cancel on the future so normal completion can take place.
+     */
+    void abort() {
+        m_abort = true;
+    }
+
+    @SuppressWarnings("resource")
+    private Void download() {
+
+        int statusCode = 0;
+        Map<String, List<String>> headerFields = null;
+
+        BufferedInputStream inputStream = null;
+        BufferedOutputStream outputStream = null;
+        HttpURLConnection httpUrlConnection = null;
+        try {
+
+            boolean partialContent = false;
+            boolean appendTarget = false;
+
+            if (m_failAtPosition == FAIL_OPENCONNECTION)
+                throw new IOException("Failed on openConnection on request");
+            httpUrlConnection = (HttpURLConnection) m_source.openConnection();
+
+            long targetSize = m_target.length();
+            if (targetSize > 0) {
+                String rangeHeader = "bytes=" + targetSize + "-";
+                m_handle.logDebug("Requesting Range %s", targetSize, rangeHeader);
+                httpUrlConnection.setRequestProperty("Range", rangeHeader);
+            }
+
+            statusCode = httpUrlConnection.getResponseCode();
+            headerFields = httpUrlConnection.getHeaderFields();
+            if (statusCode == 200) {
+                partialContent = false;
+            }
+            else if (statusCode == 206) {
+                partialContent = true;
+            }
+            else {
+                throw new IOException("Unable to handle server response code " + statusCode);
+            }
+
+            if (m_failAtPosition == FAIL_OPENINPUTSTREAM)
+                throw new IOException("Failed on openConnection on request");
+            inputStream = new BufferedInputStream(httpUrlConnection.getInputStream());
+
+            long contentLength = httpUrlConnection.getContentLength();
+            if (partialContent) {
+                String contentRange = httpUrlConnection.getHeaderField("Content-Range");
+                if (contentRange == null) {
+                    throw new IOException("Server returned no Content-Range for partial content");
+                }
+                if (!contentRange.startsWith("bytes ")) {
+                    throw new IOException("Server returned non byes Content-Range " + contentRange);
+                }
+                String tmp = contentRange;
+                tmp = tmp.replace("byes ", "");
+                String[] parts = tmp.split("/");
+                String start = parts[0].split("-")[0];
+                String end = parts[0].split("-")[1];
+                System.out.println("size:" + parts[1]);
+                System.out.println("from:" + start);
+                System.out.println("too:" + end);
+
+                if (parts[1].equals("*"))
+                    contentLength = -1;
+                else
+                    contentLength = Long.parseLong(parts[1]);
+            }
+
+            long progress = 0l;
+            if (partialContent) {
+                progress = targetSize;
+                appendTarget = true;
+            }
+
+            if (m_failAtPosition == FAIL_OPENOUTPUTSTREAM)
+                throw new IOException("Failed on outputStream");
+            outputStream = new BufferedOutputStream(new FileOutputStream(m_target, appendTarget));
+
+            byte buffer[] = new byte[m_readBufferSize];
+            int read = -1;
+            while (!m_abort && (read = inputStream.read(buffer)) >= 0) {
+
+                outputStream.write(buffer, 0, read);
+                progress += read;
+                m_handle.progressCallback(statusCode, headerFields, contentLength, progress);
+
+                if (m_failAtPosition == FAIL_AFTERFIRSTWRITE)
+                    throw new IOException("Failed after first write");
+
+                if (Thread.currentThread().isInterrupted())
+                    m_abort = true;
+            }
+
+            if (m_abort) {
+                m_handle.logDebug("Download stopped");
+                m_handle.stoppedCallback(statusCode, headerFields, null);
+            }
+            else {
+                m_handle.logDebug("Download completed");
+                m_handle.successfulCallback(statusCode, headerFields);
+            }
+        }
+        catch (Exception e) {
+            m_handle.failedCallback(statusCode, headerFields, e);
+        }
+        cleanupQuietly(httpUrlConnection, inputStream, outputStream);
+        return null;
+    }
+
+    private static void cleanupQuietly(HttpURLConnection httpUrlConnection, InputStream inputStream, OutputStream outputStream) {
+        if (httpUrlConnection != null)
+            httpUrlConnection.disconnect();
+        if (inputStream != null)
+            try {
+                inputStream.close();
+            }
+            catch (IOException e) {
+                // ignore
+            }
+        if (outputStream != null)
+            try {
+                outputStream.close();
+            }
+            catch (IOException e) {
+                // ignore
+            }
+    }
+}

Added: ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadHandleImpl.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadHandleImpl.java?rev=1513834&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadHandleImpl.java (added)
+++ ace/sandbox/bramk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadHandleImpl.java Wed Aug 14 12:22:10 2013
@@ -0,0 +1,195 @@
+/*
+ * 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.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Future;
+
+import org.apache.ace.agent.DownloadHandle;
+import org.apache.ace.agent.DownloadResult;
+import org.apache.ace.agent.DownloadState;
+
+/**
+ * A {@link DownloadHandle} implementation that supports pause/resume semantics based on HTTP Range headers assuming the
+ * server supports this feature.
+ * 
+ */
+class DownloadHandleImpl implements DownloadHandle {
+
+    private final DownloadHandlerImpl m_handler;
+    private final URL m_url;
+    private final int m_readBufferSize;
+
+    private volatile boolean m_started = false;
+    private volatile boolean m_completed = false;
+
+    private volatile Future<Void> m_future;
+    private volatile DownloadCallableImpl m_callable;
+    private volatile File m_file;
+
+    private volatile ProgressListener m_progressListener;
+    private volatile CompletedListener m_completionListener;
+
+    private volatile DownloadResult m_downloadResult;
+
+    DownloadHandleImpl(DownloadHandlerImpl handler, URL url) {
+        this(handler, url, DEFAULT_READBUFFER_SIZE);
+    }
+
+    DownloadHandleImpl(DownloadHandlerImpl handler, URL url, int readBufferSize) {
+        m_handler = handler;
+        m_url = url;
+        m_readBufferSize = readBufferSize;
+    }
+
+    @Override
+    public DownloadHandle setProgressListener(ProgressListener listener) {
+        m_progressListener = listener;
+        return this;
+    }
+
+    @Override
+    public DownloadHandle setCompletionListener(CompletedListener listener) {
+        m_completionListener = listener;
+        return this;
+    }
+
+    @Override
+    public DownloadHandle start() {
+        return start(-1);
+    }
+
+    DownloadHandle start(int failAtPosition) {
+        if (m_started)
+            throw new IllegalStateException("Can not call start on a handle that is allready started");
+        if (m_file == null) {
+            try {
+                m_file = File.createTempFile("download", ".bin");
+            }
+            catch (IOException e) {
+                failedCallback(0, null, e);
+            }
+        }
+        startDownload(failAtPosition);
+        return this;
+    }
+
+    @Override
+    public DownloadHandle stop() {
+        if (!m_started && !m_completed)
+            throw new IllegalStateException("Can not call stop on a handle that is not yet started");
+        m_started = false;
+        stopDownload();
+        return this;
+    }
+
+    @Override
+    public DownloadResult result() {
+        if (m_completed)
+            return m_downloadResult;
+        if (!m_started)
+            throw new IllegalStateException("Can not call result on a handle that is not yet started");
+        try {
+            m_future.get();
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+        return m_downloadResult;
+    }
+
+    @Override
+    public void discard() {
+        if (m_started)
+            stop();
+        m_file.delete();
+    }
+
+    void progressCallback(int statusCode, Map<String, List<String>> headers, long contentLength, long progress) {
+        callProgressListener(m_progressListener, contentLength, progress);
+    }
+
+    void successfulCallback(int statusCode, Map<String, List<String>> headers) {
+        m_started = false;
+        m_completed = true;
+        m_downloadResult = new DownloadResultImpl(DownloadState.SUCCESSFUL, m_file, statusCode, headers, null);
+        callCompletionListener(m_completionListener, m_downloadResult);
+    }
+
+    void stoppedCallback(int statusCode, Map<String, List<String>> headers, Throwable cause) {
+        m_started = false;
+        m_completed = false;
+        m_downloadResult = new DownloadResultImpl(DownloadState.STOPPED, null, statusCode, headers, cause);
+        callCompletionListener(m_completionListener, m_downloadResult);
+    }
+
+    void failedCallback(int statusCode, Map<String, List<String>> headers, Throwable cause) {
+        m_started = false;
+        m_completed = false;
+        m_downloadResult = new DownloadResultImpl(DownloadState.FAILED, null, statusCode, headers, cause);
+        callCompletionListener(m_completionListener, m_downloadResult);
+    }
+
+    void logDebug(String message, Object... args) {
+        m_handler.logDebug(message, args);
+    }
+
+    void logInfo(String message, Object... args) {
+        m_handler.logInfo(message, args);
+    }
+
+    void logWarning(String message, Object... args) {
+        m_handler.logWarning(message, args);
+    }
+
+    private void startDownload(int failAtPosition) {
+        m_started = true;
+        m_callable = new DownloadCallableImpl(this, m_url, m_file, m_readBufferSize, failAtPosition);
+        m_future = m_handler.getExecutor().submit(m_callable);
+    }
+
+    private void stopDownload() {
+        m_started = false;
+        m_callable.abort();
+    }
+
+    private static void callProgressListener(ProgressListener listener, long contentLength, long progress) {
+        if (listener != null)
+            try {
+                listener.progress(contentLength, progress);
+            }
+            catch (Exception e) {
+                // ignore
+            }
+    }
+
+    private static void callCompletionListener(CompletedListener listener, DownloadResult result) {
+        if (listener != null && result != null)
+            try {
+                listener.completed(result);
+            }
+            catch (Exception e) {
+                // ignore
+            }
+    }
+}