You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2013/10/24 11:16:58 UTC

svn commit: r1535322 - in /ace/trunk/org.apache.ace.deployment: src/org/apache/ace/deployment/servlet/ test/org/apache/ace/deployment/servlet/

Author: jawi
Date: Thu Oct 24 09:16:58 2013
New Revision: 1535322

URL: http://svn.apache.org/r1535322
Log:
ACE-330 - limit DP-versions for a target:

- some fixes found by monkey testing the earlier fix;
- basically the requested from-version needs to be verified
  if it is still present before streaming back a DP;
- took the liberty of cleaning up the code a bit for sake
  of readability;
- updated the unit tests to cover the new situation.


Added:
    ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DefaultDeploymentProcessor.java   (with props)
Modified:
    ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java
    ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java

Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DefaultDeploymentProcessor.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DefaultDeploymentProcessor.java?rev=1535322&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DefaultDeploymentProcessor.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DefaultDeploymentProcessor.java Thu Oct 24 09:16:58 2013
@@ -0,0 +1,62 @@
+/*
+ * 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.deployment.servlet;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.ace.deployment.processor.DeploymentProcessor;
+
+/**
+ * Provides a default deployment processor that simply streams all content from the deployment package back to the
+ * client.
+ */
+public class DefaultDeploymentProcessor implements DeploymentProcessor {
+
+    @Override
+    public void process(InputStream inputStream, HttpServletRequest request, HttpServletResponse response) throws IOException {
+        OutputStream output = response.getOutputStream();
+
+        try {
+            byte[] buffer = new byte[1024 * 32];
+            for (int bytesRead = inputStream.read(buffer); bytesRead != -1; bytesRead = inputStream.read(buffer)) {
+                output.write(buffer, 0, bytesRead);
+            }
+        }
+        finally {
+            closeSilently(output);
+        }
+    }
+
+    private void closeSilently(Closeable output) {
+        try {
+            if (output != null) {
+                output.close();
+            }
+        }
+        catch (IOException e) {
+            // Ignore; nothing we can do about this...
+        }
+    }
+}

Propchange: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DefaultDeploymentProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java?rev=1535322&r1=1535321&r2=1535322&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java (original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java Thu Oct 24 09:16:58 2013
@@ -79,6 +79,46 @@ public class DeploymentServlet extends H
 
     private volatile boolean m_useAuth = false;
 
+    public void addProcessor(ServiceReference ref, DeploymentProcessor processor) {
+        String key = (String) ref.getProperty(PROCESSOR);
+        if (key != null) {
+            m_processors.putIfAbsent(key, processor);
+        }
+        else {
+            m_log.log(LogService.LOG_WARNING, "Deployment processor ignored, required service property '" + PROCESSOR + "' is missing.");
+        }
+    }
+
+    @Override
+    public String getServletInfo() {
+        return "Ace Deployment Servlet Endpoint";
+    }
+
+    public void removeProcessor(ServiceReference ref, DeploymentProcessor processor) {
+        String key = (String) ref.getProperty(PROCESSOR);
+        // we do not log this here again, we already did so in 'addProcessor'
+        if (key != null) {
+            m_processors.remove(key);
+        }
+    }
+
+    @Override
+    public void updated(Dictionary settings) throws ConfigurationException {
+        if (settings != null) {
+            String useAuthString = (String) settings.get(KEY_USE_AUTHENTICATION);
+            if (useAuthString == null
+                || !("true".equalsIgnoreCase(useAuthString) || "false".equalsIgnoreCase(useAuthString))) {
+                throw new ConfigurationException(KEY_USE_AUTHENTICATION, "Missing or invalid value!");
+            }
+            boolean useAuth = Boolean.parseBoolean(useAuthString);
+
+            m_useAuth = useAuth;
+        }
+        else {
+            m_useAuth = false;
+        }
+    }
+
     /**
      * Responds to GET requests sent to this endpoint, the response depends on the requested path: <li>
      * http://host/endpoint/targetid/versions/ returns a list of versions available for the specified target <li>
@@ -128,31 +168,11 @@ public class DeploymentServlet extends H
                 String targetID = pathElements[1];
                 String version = pathElements[3];
 
-                String current = request.getParameter(CURRENT);
-
-                List<ArtifactData> artifacts;
-                if (current != null) {
-                    artifacts = m_provider.getBundleData(targetID, current, version);
-                } else {
-                    artifacts = m_provider.getBundleData(targetID, version);
-                }
-                
-                long dpSize = 0L;
-                for (ArtifactData artifactData : artifacts) {
-                    long size = artifactData.getSize();
-                    if (size > 0L) {
-                        dpSize += size;
-                    }
-                    else {
-                        dpSize = -1L;
-                        break; // cannot determine the DP size...
-                    }
-                }
-
                 response.setContentType(DP_MIMETYPE);
 
+                long dpSize = estimateDeploymentPackageSize(request, targetID, version);
                 if (dpSize > 0) {
-                    response.addHeader(HEADER_DPSIZE, Long.toString((long) (DPSIZE_FACTOR * dpSize)));
+                    response.addHeader(HEADER_DPSIZE, Long.toString(dpSize));
                 }
             }
         }
@@ -209,39 +229,85 @@ public class DeploymentServlet extends H
         return true;
     }
 
+    private long estimateDeploymentPackageSize(HttpServletRequest request, String targetID, String version) throws IOException, OverloadedException, AceRestException {
+        List<String> versions = getVersions(targetID);
+        String current = request.getParameter(CURRENT);
+
+        List<ArtifactData> artifacts;
+        if (current != null && versions.contains(current)) {
+            artifacts = m_provider.getBundleData(targetID, current, version);
+        }
+        else {
+            artifacts = m_provider.getBundleData(targetID, version);
+        }
+
+        long dpSize = 0L;
+        for (ArtifactData artifactData : artifacts) {
+            long size = artifactData.getSize();
+            if (size > 0L) {
+                dpSize += size;
+            }
+            else {
+                // cannot determine the DP size...
+                return -1L;
+            }
+        }
+        return (long) (DPSIZE_FACTOR * dpSize);
+    }
+
+    private InputStream getDeploymentPackageStream(String targetID, String version, HttpServletRequest request, List<String> versions) throws IOException {
+        String current = request.getParameter(CURRENT);
+
+        // Determine whether we should return a fix-package, or a complete deployment package. Keep in consideration
+        // that due to ACE-330, the given current-version can already be purged from the repository...
+        if (current != null && versions.contains(current)) {
+            m_log.log(LogService.LOG_DEBUG, "Generating deployment fix-package for " + current + " => " + version);
+
+            return m_streamGenerator.getDeploymentPackage(targetID, current, version);
+        }
+
+        m_log.log(LogService.LOG_DEBUG, "Generating deployment package for " + version);
+
+        return m_streamGenerator.getDeploymentPackage(targetID, version);
+    }
+
     /**
-     * Serve the case where requested path is like: http://host/endpoint/targetid/versions/ returns a list of versions
-     * available for the specified target
-     * 
-     * @param targetID
-     *            the target ID for which to return all available versions;
-     * @param response
-     *            response object.
+     * @return the requested {@link DeploymentProcessor}, or <code>null</code> in case none is requested.
+     * @throws AceRestException
+     *             in case a non-existing deployment processor was requested.
      */
-    private void handleVersionsRequest(String targetID, HttpServletResponse response) throws OverloadedException, AceRestException {
-        ServletOutputStream output = null;
+    private DeploymentProcessor getDeploymentProcessor(HttpServletRequest request) throws AceRestException {
+        String processor = request.getParameter(PROCESSOR);
+        if (processor != null) {
+            DeploymentProcessor deploymentProcessor = m_processors.get(processor);
+            if (deploymentProcessor == null) {
+                throw new AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not find a deployment processor called: " + processor);
+            }
 
-        List<String> versions = getVersions(targetID);
+            m_log.log(LogService.LOG_DEBUG, "Using deployment processor " + processor);
 
-        response.setContentType(TEXT_MIMETYPE);
+            return deploymentProcessor;
+        }
+
+        m_log.log(LogService.LOG_DEBUG, "Using default deployment processor...");
+
+        return new DefaultDeploymentProcessor();
+    }
+
+    private List<String> getVersions(String targetID) throws OverloadedException, AceRestException {
         try {
-            output = response.getOutputStream();
-            for (String version : versions) {
-                output.print(version);
-                output.print("\n");
-            }
+            return m_provider.getVersions(targetID);
         }
-        catch (IOException e) {
-            throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is invalid");
+        catch (IllegalArgumentException iae) {
+            throw new AceRestException(HttpServletResponse.SC_NOT_FOUND, "Unknown target (" + targetID + ")");
         }
-        finally {
-            tryClose(output);
+        catch (IOException ioe) {
+            m_log.log(LogService.LOG_WARNING, "Error getting available versions.", ioe);
+            throw new AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error getting available versions.");
         }
     }
 
     private void handlePackageDelivery(String targetID, String version, HttpServletRequest request, HttpServletResponse response) throws OverloadedException, AceRestException {
-        ServletOutputStream output = null;
-
         List<String> versions = getVersions(targetID);
         if (!versions.contains(version)) {
             throw new AceRestException(HttpServletResponse.SC_NOT_FOUND, "Unknown version (" + version + ")");
@@ -252,33 +318,15 @@ public class DeploymentServlet extends H
             response = new ContentRangeResponseWrapper(request, response);
             response.setContentType(DP_MIMETYPE);
 
-            String current = request.getParameter(CURRENT);
-            String processor = request.getParameter(PROCESSOR);
+            // determine the deployment processor early, as to avoid having to create a complete deployment package in
+            // case of a missing/incorrect requested processor...
+            DeploymentProcessor deploymentProcessor = getDeploymentProcessor(request);
 
-            InputStream inputStream;
-            if (current != null) {
-                inputStream = m_streamGenerator.getDeploymentPackage(targetID, current, version);
-            }
-            else {
-                inputStream = m_streamGenerator.getDeploymentPackage(targetID, version);
-            }
+            // get the input stream to the deployment package...
+            InputStream inputStream = getDeploymentPackageStream(targetID, version, request, versions);
 
-            if (processor != null) {
-                DeploymentProcessor deploymentProcessor = m_processors.get(processor);
-                if (deploymentProcessor != null) {
-                    deploymentProcessor.process(inputStream, request, response);
-                    return;
-                }
-                else {
-                    throw new AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not find a deployment processor called: " + processor);
-                }
-            }
-
-            output = response.getOutputStream();
-            byte[] buffer = new byte[1024 * 32];
-            for (int bytesRead = inputStream.read(buffer); bytesRead != -1; bytesRead = inputStream.read(buffer)) {
-                output.write(buffer, 0, bytesRead);
-            }
+            // process and send back the results to the client...
+            deploymentProcessor.process(inputStream, request, response);
         }
         catch (IllegalArgumentException e) {
             throw (AceRestException) new AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is invalid").initCause(e);
@@ -286,21 +334,35 @@ public class DeploymentServlet extends H
         catch (IOException e) {
             throw (AceRestException) new AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not deliver package").initCause(e);
         }
-        finally {
-            tryClose(output);
-        }
     }
 
-    private List<String> getVersions(String targetID) throws OverloadedException, AceRestException {
+    /**
+     * Serve the case where requested path is like: http://host/endpoint/targetid/versions/ returns a list of versions
+     * available for the specified target
+     * 
+     * @param targetID
+     *            the target ID for which to return all available versions;
+     * @param response
+     *            response object.
+     */
+    private void handleVersionsRequest(String targetID, HttpServletResponse response) throws OverloadedException, AceRestException {
+        ServletOutputStream output = null;
+
+        List<String> versions = getVersions(targetID);
+
+        response.setContentType(TEXT_MIMETYPE);
         try {
-            return m_provider.getVersions(targetID);
+            output = response.getOutputStream();
+            for (String version : versions) {
+                output.print(version);
+                output.print("\n");
+            }
         }
-        catch (IllegalArgumentException iae) {
-            throw new AceRestException(HttpServletResponse.SC_NOT_FOUND, "Unknown target (" + targetID + ")");
+        catch (IOException e) {
+            throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is invalid");
         }
-        catch (IOException ioe) {
-            m_log.log(LogService.LOG_WARNING, "Error getting available versions.", ioe);
-            throw new AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error getting available versions.");
+        finally {
+            tryClose(output);
         }
     }
 
@@ -311,8 +373,7 @@ public class DeploymentServlet extends H
             }
         }
         catch (IOException e) {
-            m_log.log(LogService.LOG_WARNING, "Exception trying to close stream after request. ", e);
-            throw new RuntimeException(e);
+            m_log.log(LogService.LOG_WARNING, "Exception trying to close stream after request.", e);
         }
     }
 
@@ -339,44 +400,4 @@ public class DeploymentServlet extends H
         }
         return elements;
     }
-
-    @Override
-    public String getServletInfo() {
-        return "Ace Deployment Servlet Endpoint";
-    }
-
-    @Override
-    public void updated(Dictionary settings) throws ConfigurationException {
-        if (settings != null) {
-            String useAuthString = (String) settings.get(KEY_USE_AUTHENTICATION);
-            if (useAuthString == null
-                || !("true".equalsIgnoreCase(useAuthString) || "false".equalsIgnoreCase(useAuthString))) {
-                throw new ConfigurationException(KEY_USE_AUTHENTICATION, "Missing or invalid value!");
-            }
-            boolean useAuth = Boolean.parseBoolean(useAuthString);
-
-            m_useAuth = useAuth;
-        }
-        else {
-            m_useAuth = false;
-        }
-    }
-
-    public void addProcessor(ServiceReference ref, DeploymentProcessor processor) {
-        String key = (String) ref.getProperty(PROCESSOR);
-        if (key == null) {
-            m_log.log(LogService.LOG_WARNING, "Deployment processor ignored, required service property '" + PROCESSOR + "' is missing.");
-            return;
-        }
-        m_processors.putIfAbsent(key, processor);
-    }
-
-    public void removeProcessor(ServiceReference ref, DeploymentProcessor processor) {
-        String key = (String) ref.getProperty(PROCESSOR);
-        if (key == null) {
-            // we do not log this here again, we already did so in 'addProcessor'
-            return;
-        }
-        m_processors.remove(key);
-    }
 }

Modified: ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java?rev=1535322&r1=1535321&r2=1535322&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java (original)
+++ ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java Thu Oct 24 09:16:58 2013
@@ -24,6 +24,9 @@ import static org.apache.ace.test.utils.
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -53,7 +56,7 @@ public class DeploymentServletTest {
     private DeploymentServlet m_servlet;
 
     private long m_artifactSize;
-    
+
     // request state
     private HttpServletRequest m_request;
     private String m_requestCurrentParameter;
@@ -106,7 +109,9 @@ public class DeploymentServletTest {
     }
 
     @Test(groups = { UNIT })
-    public void getFixPackageForExistingTarget() throws Exception {
+    public void getFixPackageForExistingTargetWithNonExistingFromVersion() throws Exception {
+        // try to request a version range with a non-existing from-version, should cause a complete (non-fix) package to
+        // be returned...
         m_requestPathInfo = "/existing/versions/2.0.0";
         m_requestCurrentParameter = "1.0.0";
         m_servlet.doGet(m_request, m_response);
@@ -114,7 +119,20 @@ public class DeploymentServletTest {
         assertResponseOutputSize(100);
         assertGeneratorTargetId("existing");
         assertGeneratorToVersion("2.0.0");
-        assertGeneratorFromVersion("1.0.0");
+        assertGeneratorFromVersion(null);
+    }
+
+    @Test(groups = { UNIT })
+    public void getFixPackageForExistingTargetWithExistingFromVersion() throws Exception {
+        // try to request a version range with an existing from-version, should cause a fix package to be returned...
+        m_requestPathInfo = "/existing/versions/2.0.0";
+        m_requestCurrentParameter = "2.0.0";
+        m_servlet.doGet(m_request, m_response);
+        assertResponseCode(HttpServletResponse.SC_OK);
+        assertResponseOutputSize(100);
+        assertGeneratorTargetId("existing");
+        assertGeneratorToVersion("2.0.0");
+        assertGeneratorFromVersion("2.0.0");
     }
 
     @Test
@@ -253,7 +271,7 @@ public class DeploymentServletTest {
         m_requestPathInfo = "/existing/versions";
         m_servlet.doGet(m_request, m_response);
         assertResponseCode(HttpServletResponse.SC_OK);
-        assert "2.0.0\n".equals(m_responseOutputStream.toString()) : "Expected to get version 2.0.0 in the response";
+        assertEquals(m_responseOutputStream.toString(), "2.0.0\n", "Expected to get version 2.0.0 in the response");
     }
 
     @Test
@@ -408,31 +426,31 @@ public class DeploymentServletTest {
     }
 
     private void assertGeneratorFromVersion(String version) {
-        assert m_generatorFromVersion.equals(version) : "Wrong version.";
+        assertEquals(m_generatorFromVersion, version, "Wrong from-version");
     }
 
     private void assertGeneratorTargetId(String id) {
-        assert m_generatorId.equals(id) : "Wrong target ID.";
+        assertEquals(m_generatorId, id, "Wrong target ID");
     }
 
     private void assertGeneratorToVersion(String version) {
-        assert m_generatorToVersion.equals(version) : "Wrong version.";
+        assertEquals(m_generatorToVersion, version, "Wrong to-version");
     }
 
     private void assertResponseCode(int value) throws Exception {
-        assert m_responseStatus == value : "We should have got response code " + value + " but got " + m_responseStatus;
+        assertEquals(m_responseStatus, value, "Incorrect response code from server");
     }
 
     private void assertResponseHeaderNotPresent(String name) throws Exception {
-        assert !m_responseHeaders.containsKey(name) : "Expected response " + name + " header to NOT be set";
+        assertFalse(m_responseHeaders.containsKey(name), "Expected response " + name + " header to NOT be set");
     }
 
     private void assertResponseHeaderValue(String name, String value) throws Exception {
-        assert m_responseHeaders.containsKey(name) : "Expected response " + name + " header to be set";
-        assert m_responseHeaders.get(name).equals(value) : "Expected " + name + " header with value '" + value + "' and got '" + m_responseHeaders.get(name) + "'";
+        assertTrue(m_responseHeaders.containsKey(name), "Expected response " + name + " header to be set");
+        assertEquals(m_responseHeaders.get(name), value, "Unexpected response header");
     }
 
     private void assertResponseOutputSize(long size) throws Exception {
-        assert m_responseOutputStream.size() == size : "We should have got a (dummy) deployment package of " + size + " bytes but got " + m_responseOutputStream.size();
+        assertEquals(m_responseOutputStream.size(), size, "We should have got a (dummy) deployment package of");
     }
 }