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;
+ }
+}