You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ma...@apache.org on 2010/08/11 20:17:58 UTC

svn commit: r984509 - in /incubator/ace/trunk/ace-client-repository-helper-base: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/ace/ src/main/java/org/apache/ace/client/ src/main/java/org/apache/a...

Author: marrs
Date: Wed Aug 11 18:17:58 2010
New Revision: 984509

URL: http://svn.apache.org/viewvc?rev=984509&view=rev
Log:
New bundle.

Added:
    incubator/ace/trunk/ace-client-repository-helper-base/
    incubator/ace/trunk/ace-client-repository-helper-base/osgi.bnd
    incubator/ace/trunk/ace-client-repository-helper-base/pom.xml
    incubator/ace/trunk/ace-client-repository-helper-base/src/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java
    incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java

Added: incubator/ace/trunk/ace-client-repository-helper-base/osgi.bnd
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-repository-helper-base/osgi.bnd?rev=984509&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-repository-helper-base/osgi.bnd (added)
+++ incubator/ace/trunk/ace-client-repository-helper-base/osgi.bnd Wed Aug 11 18:17:58 2010
@@ -0,0 +1,53 @@
+Bundle-Version>:\
+  ${pom.version}
+
+Bundle-SymbolicName:\
+  ${bundle.symbolicName}
+
+Export-Package: \
+	${bundle.namespace}
+
+Import-Package: \
+	!javax.security.auth, \
+	!javax.swing.plaf, \
+	!javax.xml.parsers, \
+	!javax.xml.stream, \
+	!javax.xml.transform.sax, \
+	!net.sf.cglib.proxy, \
+	!nu.xom, \
+	!org.codehaus.jettison.mapped, \
+	!org.dom4j, \
+	!org.dom4j.io, \
+	!org.dom4j.tree, \
+	!org.jdom, \
+	!org.jdom.input, \
+	!org.joda.time, \
+	!org.joda.time.format, \
+	!org.w3c.dom, \
+	!org.xml.sax, \
+	!org.xml.sax.helpers, \
+	!sun.misc, \
+	!sun.reflect, \
+	!com.werken.xpath, \
+	!javax.naming, \
+	!javax.servlet, \
+	!javax.servlet.http, \
+	!javax.sql, \
+	!org.apache.commons.collections, \
+	!org.apache.commons.collections.map, \
+	!org.apache.commons.lang, \
+	!org.apache.commons.lang.builder, \
+	!org.apache.commons.lang.text, \
+	!org.apache.commons.logging, \
+	!org.apache.log, \
+	!org.apache.log.format, \
+	!org.apache.log.output.io, \
+	!org.apache.log4j, \
+	!org.apache.oro.text.perl, \
+	!org.apache.tools.ant, \
+	!org.apache.tools.ant.taskdefs, \
+	!org.jdom.output, \
+	*
+
+Embed-Dependency: \
+	velocity, xpp3

Added: incubator/ace/trunk/ace-client-repository-helper-base/pom.xml
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-repository-helper-base/pom.xml?rev=984509&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-repository-helper-base/pom.xml (added)
+++ incubator/ace/trunk/ace-client-repository-helper-base/pom.xml Wed Aug 11 18:17:58 2010
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.0-SNAPSHOT</version>
+        <relativePath>../pom/</relativePath>
+    </parent>
+
+    <groupId>org.apache.ace</groupId>
+    <artifactId>ace-client-repository-helper-base</artifactId>
+    <version>0.8.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache ACE - Client Repository Helper Base</name>
+
+    <properties>
+        <bundle.symbolicName>${namespace}.client.repository.helper.base</bundle.symbolicName>
+        <bundle.namespace>${namespace}.client.repository.helper.base</bundle.namespace>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ace-log</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ace-deployment-provider-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ace-client-repository-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>xpp3</groupId>
+            <artifactId>xpp3</artifactId>
+            <version>1.1.4c</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file

Added: incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java?rev=984509&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java (added)
+++ incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java Wed Aug 11 18:17:58 2010
@@ -0,0 +1,180 @@
+/*
+ * 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.client.repository.helper.base;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.ace.client.repository.helper.ArtifactPreprocessor;
+import org.apache.ace.client.repository.helper.PropertyResolver;
+
+/**
+ * This class can be used as a base class for artifact preprocessors. It comes with its
+ * own upload() method, which will be used by all artifact preprocessors anyway.
+ */
+public abstract class ArtifactPreprocessorBase implements ArtifactPreprocessor {
+
+    private static final int BUFFER_SIZE = 4 * 1024;
+
+    /**
+     * Uploads an artifact to an OBR.
+     * @param input A inputstream from which the artifact can be read.
+     * @param name The name of the artifact. If the name is not unique, an IOException will be thrown.
+     * @param obrBase The base URL of the obr to which this artifact should be written.
+     * @return A URL to the uploaded artifact; this is identical to calling <code>determineNewUrl(name, obrBase)</code>
+     * @throws IOException If there was an error reading from <code>input</code>, or if there was a problem communicating
+     * with the OBR.
+     */
+    protected URL upload(InputStream input, String name, URL obrBase) throws IOException {
+        if (obrBase == null) {
+            throw new IOException("There is no storage available for this artifact.");
+        }
+        if ((name == null) || (input == null)) {
+            throw new IllegalArgumentException("None of the parameters can be null.");
+        }
+
+        OutputStream output = null;
+        URL url = null;
+        try {
+            url = determineNewUrl(name, obrBase);
+            URLConnection connection = url.openConnection();
+            connection.setDoOutput(true);
+            connection.setDoInput(true);
+            output = connection.getOutputStream();
+            byte[] buffer = new byte[BUFFER_SIZE];
+            for (int count = input.read(buffer); count != -1; count = input.read(buffer)) {
+                output.write(buffer, 0, count);
+            }
+            output.close();
+            if (connection instanceof HttpURLConnection) {
+                int responseCode = ((HttpURLConnection) connection).getResponseCode();
+                switch (responseCode) {
+                    case HttpURLConnection.HTTP_OK :
+                        break;
+                    case HttpURLConnection.HTTP_CONFLICT:
+                        throw new IOException("Artifact already exists in storage.");
+                    case HttpURLConnection.HTTP_INTERNAL_ERROR:
+                        throw new IOException("The storage server returned an internal server error.");
+                    default:
+                        throw new IOException("The storage server returned code " + responseCode + " writing to " + url.toString());
+                }
+            }
+        }
+        catch (IOException ioe) {
+            throw new IOException("Error uploading " + name + ": " + ioe.getMessage());
+        }
+        finally {
+            if (input != null) {
+                try {
+                    input.close();
+                }
+                catch (Exception ex) {
+                    // Not much we can do
+                }
+            }
+            if (output != null) {
+                try {
+                    output.close();
+                }
+                catch (Exception ex) {
+                    // Not much we can do
+                }
+            }
+        }
+
+        return url;
+    }
+
+    /**
+     * Gets a stream to write an artifact to, which will be uploaded to the OBR.
+     * @param name The name of the artifact.
+     * @param obrBase The base URL of the obr to which this artifact should be written.
+     * @return An outputstream, to which the artifact can be written.
+     * @throws IOException If there is a problem setting up the outputstream.
+     */
+    protected OutputStream upload(final String name, final URL obrBase) throws IOException {
+        /*
+         * This function works by starting a thread which reads from the outputstream which is passed out,
+         * and writing it to another stream, which is read by a thread that does the Upload.
+         */
+        PipedOutputStream externalOutput = new PipedOutputStream();
+        final PipedInputStream externalInput = new PipedInputStream(externalOutput);
+
+        final PipedOutputStream internalOutput = new PipedOutputStream();
+        final PipedInputStream internalInput = new PipedInputStream(internalOutput);
+
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    byte[] buffer = new byte[BUFFER_SIZE];
+                    for (int count = externalInput.read(buffer); count != -1; count = externalInput.read(buffer)) {
+                        internalOutput.write(buffer, 0, count);
+                    }
+                }
+                catch (IOException e) {
+                    // We cannot signal this to the user, but he will notice (in the original thread)
+                    // that the pipe has been broken.
+                }
+                finally {
+                    try {
+                        internalOutput.close();
+                    }
+                    catch (IOException e) {
+                        // Not much to be done.
+                    }
+                    try {
+                        externalInput.close();
+                    }
+                    catch (IOException e) {
+                        // Not much to be done.
+                    }
+                }
+            }
+        }, "upload-Outputstream(" + name + ")").start();
+
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    upload(internalInput, name, obrBase);
+                }
+                catch (IOException e) {
+                    // We cannot signal this to the user, but he will notice (in the original thread)
+                    // that the pipe has been broken.
+                }
+            }
+        }, "upload-Inputstream(" + name + ")").start();
+
+        return externalOutput;
+    }
+
+    protected URL determineNewUrl(String name, URL obrBase) throws MalformedURLException {
+        return new URL(obrBase, name);
+    }
+
+    public abstract String preprocess(String url, PropertyResolver props, String gatewayID, String version, URL obrBase) throws IOException;
+
+    public abstract boolean needsNewVersion(String url, PropertyResolver props, String gatewayID, String fromVersion);
+}

Added: incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java?rev=984509&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java (added)
+++ incubator/ace/trunk/ace-client-repository-helper-base/src/main/java/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java Wed Aug 11 18:17:58 2010
@@ -0,0 +1,246 @@
+/*
+ * 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.client.repository.helper.base;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ace.client.repository.helper.PropertyResolver;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+
+/**
+ * This class can be used as a 'default' artifact preprocessor, using the Velocity template engine to preprocess
+ * the artifact.
+ */
+public class VelocityArtifactPreprocessor extends ArtifactPreprocessorBase {
+
+    private static final int BUFFER_SIZE = 1024;
+    private Map<String, byte[]> m_cachedArtifacts = new HashMap<String, byte[]>();
+    private Map<String, String> m_cachedHashes = new HashMap<String, String>();
+
+    private static Object m_initLock = new Object();
+    private static boolean m_velocityInitialized = false;
+
+    private void init() throws IOException {
+        if (m_velocityInitialized) {
+            return;
+        }
+        else {
+            synchronized (m_initLock) {
+                if (!m_velocityInitialized) {
+                    try {
+                        Velocity.init();
+                        m_velocityInitialized = true;
+                    }
+                    catch (Exception e) {
+                        // Something went seriously bad initializing velocity.
+                        throw new IOException("Error initializing Velocity: " + e.getMessage());
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public String preprocess(String url, PropertyResolver props, String gatewayID, String version, URL obrBase) throws IOException {
+        init();
+        // first, get the original data.
+        byte[] input = null;
+        try {
+            input = getArtifactAsBytes(url);
+        }
+        catch (IOException ioe) {
+            throw new IOException("Error retrieving the original artifact for preprocessing: " + ioe.getMessage());
+        }
+
+        // process the template
+        byte[] result = process(input, props);
+
+        if (Arrays.equals(result, input)) {
+            return url;
+        }
+        else {
+            try {
+                String name = getFilename(url, gatewayID, version);
+                OutputStream output = upload(name, obrBase);
+                output.write(result);
+                output.close();
+                setHashForVersion(url, gatewayID, version, hash(result));
+                return determineNewUrl(name, obrBase).toString();
+            }
+            catch (IOException ioe) {
+                throw new IOException("Error storing the processed: " + ioe.getMessage());
+            }
+        }
+    }
+
+    private String getFilename(String url, String gatewayID, String version) throws MalformedURLException {
+        return new File(new URL(url).getFile()).getName() + "-" + gatewayID + "-" + version;
+    }
+
+    private String getFullUrl(String url, String gatewayID, String version) throws MalformedURLException {
+        return url + "-" + gatewayID + "-" + version;
+    }
+
+    private String getHashForVersion(String url, String gateway, String version) {
+        String key = new StringBuilder().append('[')
+        .append(url)
+        .append("][")
+        .append(gateway)
+        .append("][")
+        .append(version)
+        .append(']').toString();
+
+        if (m_cachedHashes.containsKey(key)) {
+            return m_cachedHashes.get(key);
+        }
+        else {
+            byte[] processedTemplate;
+            try {
+                processedTemplate = getBytesFromUrl(getFullUrl(url, gateway, version));
+            }
+            catch (IOException e) {
+                // we cannot retrieve the artifact, so we cannot say anything about it.
+                return null;
+            }
+            String result = hash(processedTemplate);
+
+            m_cachedHashes.put(key, result);
+            return result;
+        }
+    }
+
+    private void setHashForVersion(String url, String gateway, String version, String hash) {
+        String key = new StringBuilder().append('[')
+        .append(url)
+        .append("][")
+        .append(gateway)
+        .append("][")
+        .append(version)
+        .append(']').toString();
+
+        m_cachedHashes.put(key, hash);
+    }
+
+    private byte[] process(byte[] input, PropertyResolver props) throws IOException {
+        try {
+            VelocityContext context = new VelocityContext();
+            context.put("context", props);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            Writer writer = new OutputStreamWriter(baos);
+            Velocity.evaluate(context, writer, "", new InputStreamReader(new ByteArrayInputStream(input)));
+            writer.flush();
+            return baos.toByteArray();
+        }
+        catch (IOException ioe) {
+            throw new IOException("Error processing the artifact: " + ioe.getMessage());
+        }
+    }
+
+    /**
+     * Helper method, which reads all information from a stream, and returns that as a
+     * byte array. The byte array is not to be changed.
+     */
+    private byte[] getArtifactAsBytes(String url) throws IOException {
+        if (m_cachedArtifacts.containsKey(url)) {
+            return m_cachedArtifacts.get(url);
+        }
+        else {
+            return getBytesFromUrl(url);
+        }
+    }
+
+    private byte[] getBytesFromUrl(String url) throws IOException, MalformedURLException {
+        ByteArrayOutputStream found = new ByteArrayOutputStream();
+        InputStream in = new URL(url).openStream();
+
+        byte[] buf = new byte[BUFFER_SIZE];
+        for (int count = in.read(buf); count != -1; count = in.read(buf)) {
+            found.write(buf, 0, count);
+        }
+        in.close();
+        byte[] result = found.toByteArray();
+        m_cachedArtifacts.put(url, result);
+        return result;
+    }
+
+    @Override
+    public boolean needsNewVersion(String url, PropertyResolver props, String gatewayID, String fromVersion) {
+        try {
+            init();
+        }
+        catch (IOException e) {
+            // problem initializing velocity... we cannot say anything.
+            return true;
+        }
+        // get the tempate
+        byte[] input = null;
+        byte[] result = null;
+        try {
+            input = getArtifactAsBytes(url);
+            result = process(input, props);
+        }
+        catch (IOException ioe) {
+            // we cannot retrieve the original artifact, or process it; we can't say anyting now.
+            return true;
+        }
+
+        // process the template
+
+        // first check: did we need any processing at all?
+        if (Arrays.equals(result, input)) {
+            return false;
+        }
+
+        // hash the processed template
+        String newHash = hash(result);
+
+        // find the hash for the previous version
+        String oldHash = getHashForVersion(url, gatewayID, fromVersion);
+
+        // Note: we do not cache any previously created processed templates, since the call that asks us to approve a new version
+        // may cross a pending needsNewVersion call.
+        return !newHash.equals(oldHash);
+    }
+
+    private String hash(byte[] input) {
+        try {
+            return new String(MessageDigest.getInstance("MD5").digest(input));
+        }
+        catch (NoSuchAlgorithmException e) {
+            // Will not happen: MD5 is a standard algorithm.
+        }
+        return null;
+    }
+}