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/06/24 15:12:51 UTC

svn commit: r1496021 - in /ace/sandbox/bramk/org.apache.ace.cli: ./ src/org/apache/ace/cli/deployment/ src/org/apache/ace/cli/repository/ test/org/ test/org/apache/ test/org/apache/ace/ test/org/apache/ace/cli/ test/org/apache/ace/cli/deployment/

Author: bramk
Date: Mon Jun 24 13:12:50 2013
New Revision: 1496021

URL: http://svn.apache.org/r1496021
Log:
[sandbox] Added initial code for continuous deployment

Added:
    ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/
    ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/ContinuousDeployer.java
    ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/DeployerUtil.java
    ace/sandbox/bramk/org.apache.ace.cli/test/org/
    ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/
    ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/
    ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/
    ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/
    ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/ContinuousDeployerTest.java
    ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/DeployerUtilTest.java
Modified:
    ace/sandbox/bramk/org.apache.ace.cli/bnd.bnd
    ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/repository/AceObrRepository.java

Modified: ace/sandbox/bramk/org.apache.ace.cli/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.cli/bnd.bnd?rev=1496021&r1=1496020&r2=1496021&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.cli/bnd.bnd (original)
+++ ace/sandbox/bramk/org.apache.ace.cli/bnd.bnd Mon Jun 24 13:12:50 2013
@@ -1,15 +1,19 @@
--buildpath: biz.aQute.bnd;version=2.1.0,\
-	biz.aQute.repository;version=2.1.0,\
+-buildpath: biz.aQute.repository;version=2.1.0,\
+	biz.aQute.bnd;version=2.1.0,\
 	com.google.gson,\
 	org.amdatu.ace.client,\
 	org.apache.commons.cli,\
-	org.osgi.impl.bundle.repoindex.lib
+	org.osgi.impl.bundle.repoindex.lib,\
+	junit.osgi
+
+-removeheaders: Bnd-LastModified
 
 Private-Package: \
 	org.apache.commons.cli,\
 	org.apache.ace.cli,\
 	org.apache.ace.cli.command,\
 	org.apache.ace.cli.repository,\
+	org.apache.ace.cli.deployment,\
 	org.amdatu.ace.client,\
 	org.amdatu.ace.client.model,\
 	com.google.gson.*,\

Added: ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/ContinuousDeployer.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/ContinuousDeployer.java?rev=1496021&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/ContinuousDeployer.java (added)
+++ ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/ContinuousDeployer.java Mon Jun 24 13:12:50 2013
@@ -0,0 +1,169 @@
+package org.apache.ace.cli.deployment;
+
+import static org.apache.ace.cli.deployment.DeployerUtil.copyResources;
+import static org.apache.ace.cli.deployment.DeployerUtil.findResources;
+import static org.apache.ace.cli.deployment.DeployerUtil.getIdentity;
+import static org.apache.ace.cli.deployment.DeployerUtil.getIdentityVersionRequirement;
+import static org.apache.ace.cli.deployment.DeployerUtil.getJarWithNewVersion;
+import static org.apache.ace.cli.deployment.DeployerUtil.getNextSnapshotVersion;
+import static org.apache.ace.cli.deployment.DeployerUtil.getString;
+import static org.apache.ace.cli.deployment.DeployerUtil.getVersion;
+import static org.apache.ace.cli.deployment.DeployerUtil.isSameBaseVersion;
+import static org.apache.ace.cli.deployment.DeployerUtil.jarsDiffer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.osgi.framework.Version;
+import org.osgi.resource.Resource;
+
+import aQute.bnd.deployer.repository.FixedIndexedRepo;
+import aQute.bnd.service.Strategy;
+
+public class ContinuousDeployer {
+
+    FixedIndexedRepo m_deploymentRepo;
+    FixedIndexedRepo m_developmentRepo;
+    FixedIndexedRepo m_releaseRepo;
+
+    public ContinuousDeployer(FixedIndexedRepo deploymentRepo, FixedIndexedRepo developmentRepo, FixedIndexedRepo releaseRepo) {
+        m_deploymentRepo = deploymentRepo;
+        m_developmentRepo = developmentRepo;
+        m_releaseRepo = releaseRepo;
+    }
+
+    /**
+     * Deploys all resources from the development respsitory into the deployment repository.
+     * 
+     * @return
+     * @throws Exception
+     */
+    public List<Resource> deployResources() throws Exception {
+        List<Resource> resources = findResources(m_developmentRepo, "*", "*");
+        for (Resource resource : resources) {
+            System.out.println("Deploying resource:  " + getString(resource));
+            deployResource(resource);
+        }
+        return resources;
+    }
+
+    /**
+     * Deploys a resource to the deployment repository.
+     * 
+     * @param resource
+     *            The resource
+     * @throws Exception
+     *             On failure
+     */
+    private void deployResource(Resource resource) throws Exception {
+        List<Resource> releaseResources = findResources(m_releaseRepo, getIdentity(resource), getVersion(resource).toString());
+        boolean isReleased = releaseResources.size() > 0;
+        if (isReleased) {
+            System.out.println("Deploying release:  " + getString(resource));
+            deployReleasedResource(resource);
+        }
+        else {
+            System.out.println("Deploying snapshot:  " + getString(resource));
+            deploySnapshotResource(resource);
+        }
+    }
+
+    /**
+     * Deploys a released resource from the release repository to the deployment repository if it has not been deployed
+     * yet.
+     * 
+     * @param resource
+     *            The resource
+     * @throws Exception
+     *             On failure
+     */
+    private void deployReleasedResource(Resource resource) throws Exception {
+        List<Resource> deployedResources = findResources(m_deploymentRepo, getIdentity(resource), getVersion(resource).toString());
+        boolean isDeployed = deployedResources.size() > 0;
+        if (!isDeployed) {
+            System.out.println("Uploading release:  " + getString(resource));
+            copyResources(m_releaseRepo, m_deploymentRepo, getIdentityVersionRequirement(resource));
+        }
+        else {
+            System.out.println("Ignoring release:  " + getString(resource));
+        }
+    }
+
+    /**
+     * Deploys a snapshot resource to the deployment repository if it differs from the highest existing snapshot
+     * resource of the same base version in the deployment repository.
+     * 
+     * @param resource
+     *            The resource
+     * @throws Exception
+     *             On failure
+     */
+    private void deploySnapshotResource(Resource resource) throws Exception {
+
+        Version releasedBaseVersion = getReleasedBaseVersion(resource);
+        Resource snapshotResource = getHighestSnapshotResource(resource, releasedBaseVersion);
+        if (snapshotResource == null) {
+            System.out.println("Uploading initial snapshot:  " + getNextSnapshotVersion(releasedBaseVersion));
+            deploySnapshotResource(resource, getNextSnapshotVersion(releasedBaseVersion));
+        }
+        else {
+            System.out.println("Found existing snapshot:  " + getString(snapshotResource));
+
+            File developmentResource = m_developmentRepo.get(getIdentity(resource), getVersion(resource).toString(), Strategy.EXACT, null);
+            File deployedResource = m_deploymentRepo.get(getIdentity(snapshotResource), getVersion(snapshotResource).toString(), Strategy.EXACT, null);
+            File comparableDeployedResource = getJarWithNewVersion(deployedResource, getVersion(resource).toString());
+
+            if (jarsDiffer(comparableDeployedResource, developmentResource)) {
+                System.out.println("Uploading new snapshot:  " + getNextSnapshotVersion(getVersion(snapshotResource)));
+                deploySnapshotResource(resource, getNextSnapshotVersion(getVersion(snapshotResource)));
+            }
+            else {
+                System.out.println("Ignoring new snapshot:  " + getString(resource));
+            }
+        }
+    }
+
+    private void deploySnapshotResource(Resource resource, Version snapshotVersion) throws Exception {
+
+        File file = m_developmentRepo.get(getIdentity(resource), getVersion(resource).toString(), Strategy.EXACT, null);
+        File snapshotVersionedJar = getJarWithNewVersion(file, snapshotVersion.toString());
+        InputStream input = null;
+        try {
+            input = new FileInputStream(snapshotVersionedJar);
+            m_deploymentRepo.put(input, null);
+        }
+        finally {
+            if (input != null)
+                input.close();
+        }
+    }
+
+    private Resource getHighestSnapshotResource(Resource resource, Version base) throws Exception {
+        List<Resource> resources = findResources(m_deploymentRepo, getIdentity(resource));
+        Resource matchedResource = null;
+        for (Resource candidateResource : resources) {
+            if (isSameBaseVersion(getVersion(candidateResource), base)
+                && (matchedResource == null || getVersion(matchedResource).compareTo(getVersion(candidateResource)) < 0)) {
+                matchedResource = candidateResource;
+            }
+        }
+        return matchedResource;
+    }
+
+    private Version getReleasedBaseVersion(Resource resource) throws Exception {
+        List<Resource> resources = findResources(m_releaseRepo, getIdentity(resource));
+        Version resourceVersion = getVersion(resource);
+        Version baseVersion = Version.emptyVersion;
+        for (Resource candidate : resources) {
+            Version candidateVersion = getVersion(candidate);
+            if (candidateVersion.compareTo(resourceVersion) < 0) {
+                if (candidateVersion.compareTo(baseVersion) > 0) {
+                    baseVersion = candidateVersion;
+                }
+            }
+        }
+        return baseVersion;
+    }
+}

Added: ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/DeployerUtil.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/DeployerUtil.java?rev=1496021&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/DeployerUtil.java (added)
+++ ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/deployment/DeployerUtil.java Mon Jun 24 13:12:50 2013
@@ -0,0 +1,327 @@
+package org.apache.ace.cli.deployment;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import org.osgi.framework.Version;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.service.repository.Repository;
+
+import aQute.bnd.deployer.repository.AbstractIndexedRepo;
+import aQute.bnd.differ.DiffPluginImpl;
+import aQute.bnd.osgi.Jar;
+import aQute.bnd.osgi.resource.CapReqBuilder;
+import aQute.bnd.service.Strategy;
+import aQute.bnd.service.diff.Delta;
+import aQute.bnd.service.diff.Diff;
+import aQute.bnd.service.diff.Differ;
+import aQute.bnd.service.diff.Tree;
+
+public final class DeployerUtil {
+
+    public static final String QUALIFIER_PREFIX = "CDS";
+
+    private static final Pattern QUALIFIER_PATTERN = Pattern.compile(QUALIFIER_PREFIX + "([\\d]{3})$|(.*)(_" + QUALIFIER_PREFIX + "([\\d]{3})?$)");
+
+    /**
+     * Given ad version, creates the 'next' snapshot version. If the version has no snapshot qualifier a new one will be
+     * added. If it does, it will be incremented.
+     * 
+     * @param version
+     *            The version
+     * @return The next snapshot Version
+     * @throws Exception
+     *             On Failure
+     */
+    public static Version getNextSnapshotVersion(Version version) throws Exception {
+
+        if (version.getQualifier() == null || version.getQualifier().equals("")) {
+            return new Version(version.getMajor(), version.getMinor(), version.getMicro(), getSnapshotQualifier("", 0));
+        }
+        Matcher qualifierMatcher = QUALIFIER_PATTERN.matcher(version.getQualifier());
+        if (!qualifierMatcher.matches()) {
+            return new Version(version.getMajor(), version.getMinor(), version.getMicro(), getSnapshotQualifier(version.getQualifier(), 0));
+        }
+
+        String qualifierMatch = qualifierMatcher.group(1);
+        if (qualifierMatch != null) {
+            int sequence = Integer.parseInt(qualifierMatch);
+            return new Version(version.getMajor(), version.getMinor(), version.getMicro(), getSnapshotQualifier("", ++sequence));
+        }
+
+        String qualifierPrefix = qualifierMatcher.group(2);
+        qualifierMatch = qualifierMatcher.group(4);
+        int sequence = Integer.parseInt(qualifierMatch);
+        return new Version(version.getMajor(), version.getMinor(), version.getMicro(), getSnapshotQualifier(qualifierPrefix, ++sequence));
+    }
+
+    /**
+     * Check if there is a diff between two jar files.
+     * 
+     * @param first
+     *            The first Jar file
+     * @param second
+     *            The second Jar file
+     * @return <code>true</code> if there is a difference, otherwise <code>false</code>
+     * @throws Exception
+     *             On failure
+     */
+    public static boolean jarsDiffer(File first, File second) throws Exception {
+
+        Differ di = new DiffPluginImpl();
+        Tree n = di.tree(new Jar(second));
+        Tree o = di.tree(new Jar(first));
+
+        Diff diff = n.diff(o);
+        for (Diff child : diff.getChildren()) {
+            for (Diff childc : child.getChildren()) {
+                if (childc.getDelta() == Delta.UNCHANGED || childc.getDelta() == Delta.IGNORED) {
+                    continue;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Clones a jar file while replacing the Bundle-Version in the manifest with the specified value.
+     * 
+     * @param sourceJar
+     *            The existing jar
+     * @param version
+     *            The new version
+     * @return The new Jar
+     * @throws IOException
+     *             On failure
+     */
+    public static File getJarWithNewVersion(File sourceJar, String version) throws IOException {
+
+        File targetFile = File.createTempFile("bundle", ".jar");
+        byte[] buf = new byte[1024];
+
+        ZipInputStream zin = new ZipInputStream(new FileInputStream(sourceJar));
+        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(targetFile));
+        ZipEntry entry = zin.getNextEntry();
+        while (entry != null) {
+            String name = entry.getName();
+            out.putNextEntry(new ZipEntry(name));
+
+            if (name.equals("META-INF/MANIFEST.MF")) {
+                ByteBuffer bb = ByteBuffer.allocate(10 * 1024);
+                int len;
+                while ((len = zin.read(buf)) > 0) {
+                    bb.put(buf, 0, len);
+                }
+
+                BufferedReader r = new BufferedReader(new StringReader(new String(bb.array(), 0, bb.position())));
+                String line;
+                while ((line = r.readLine()) != null) {
+                    if (line.startsWith("Bundle-Version:")) {
+                        out.write(("Bundle-Version: " + version + "\r\n").getBytes());
+                    }
+                    else {
+                        out.write((line + "\r\n").getBytes());
+                    }
+                }
+            }
+            else {
+                int len;
+                while ((len = zin.read(buf)) > 0) {
+                    out.write(buf, 0, len);
+                }
+            }
+            entry = zin.getNextEntry();
+        }
+        zin.close();
+        out.close();
+        return targetFile;
+    }
+
+    public static String getString(Resource resource) {
+        return getIdentity(resource) + "/" + getVersion(resource) + "/" + getType(resource);
+    }
+
+    public static String getIdentity(Resource resource) {
+        Map<String, Object> attrs = getNamespaceAttributes(resource, "osgi.identity");
+        if (attrs == null)
+            return null;
+        return (String) attrs.get("osgi.identity");
+
+    }
+
+    public static Requirement getIdentityVersionRequirement(Resource resource) {
+        Requirement requirement = new CapReqBuilder("osgi.identity")
+            .addDirective("filter", String.format("(&(osgi.identity=%s)(version=%s)(type=*))", getIdentity(resource), getVersion(resource)))
+            .buildSyntheticRequirement();
+        return requirement;
+    }
+
+    public static List<Resource> copyResources(AbstractIndexedRepo fromRepo, AbstractIndexedRepo toRepo, String bsn) throws Exception {
+        return copyResources(fromRepo, toRepo, bsn, "*");
+    }
+
+    public static List<Resource> copyResources(AbstractIndexedRepo fromRepo, AbstractIndexedRepo toRepo, String bsn, String version) throws Exception {
+        return copyResources(fromRepo, toRepo, bsn, version, "*");
+    }
+
+    public static List<Resource> copyResources(AbstractIndexedRepo fromRepo, AbstractIndexedRepo toRepo, String bsn, String version, String type) throws Exception {
+        Requirement requirement = new CapReqBuilder("osgi.identity")
+            .addDirective("filter", String.format("(&(osgi.identity=%s)(version=%s)(type=%s))", bsn, version, type))
+            .buildSyntheticRequirement();
+        return copyResources(fromRepo, toRepo, requirement);
+    }
+
+    public static List<Resource> copyResources(AbstractIndexedRepo fromRepo, AbstractIndexedRepo toRepo, Requirement requirement) throws Exception {
+        List<Resource> resources = findResources(fromRepo, requirement);
+        for (Resource resource : resources) {
+            File file = fromRepo.get(getIdentity(resource), getVersion(resource).toString(), Strategy.EXACT, null);
+            InputStream input = null;
+            try {
+                input = new FileInputStream(file);
+                toRepo.put(input, null);
+            }
+            finally {
+                if (input != null)
+                    input.close();
+            }
+        }
+        return resources;
+    }
+
+    public static List<Resource> findResources(Repository repository, String bsn) {
+        return findResources(repository, bsn, "*");
+    }
+
+    public static List<Resource> findResources(Repository repository, String bsn, String version) {
+        return findResources(repository, bsn, version, "*");
+    }
+
+    public static List<Resource> findResources(Repository repository, String bsn, String version, String type) {
+        Requirement requirement = new CapReqBuilder("osgi.identity")
+            .addDirective("filter", String.format("(&(osgi.identity=%s)(version=%s)(type=%s))", bsn, version, type))
+            .buildSyntheticRequirement();
+        return findResources(repository, requirement);
+    }
+
+    public static List<Resource> findResources(Repository repository, Requirement requirement) {
+        Map<Requirement, Collection<Capability>> sourceResources = repository.findProviders(Collections.singleton(requirement));
+        if (sourceResources.isEmpty() || sourceResources.get(requirement).isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<Resource> resources = new ArrayList<Resource>();
+        Iterator<Capability> capabilities = sourceResources.get(requirement).iterator();
+        while (capabilities.hasNext()) {
+            Capability capability = capabilities.next();
+            resources.add(capability.getResource());
+        }
+        return resources;
+    }
+
+    public static Version getVersion(Resource resource) {
+        Map<String, Object> attrs = getNamespaceAttributes(resource, "osgi.identity");
+        if (attrs == null)
+            return Version.emptyVersion;
+        Version version = (Version) attrs.get("version");
+        return version == null ? Version.emptyVersion : version;
+    }
+
+    public static List<Version> getVersions(List<Resource> resources) {
+        List<Version> versions = new ArrayList<Version>();
+        for (Resource resource : resources) {
+            versions.add(getVersion(resource));
+        }
+        return versions;
+    }
+
+    public static String getType(Resource resource) {
+        Map<String, Object> attrs = getNamespaceAttributes(resource, "osgi.identity");
+        if (attrs == null)
+            return null;
+        return (String) attrs.get("type");
+    }
+
+    public static String getUrl(Resource resource) {
+        Map<String, Object> attrs = getNamespaceAttributes(resource, "osgi.content");
+        if (attrs == null)
+            return null;
+        URI url = (URI) attrs.get("url");
+        return url == null ? null : url.toString();
+    }
+
+    public static String getMimetype(Resource resource) {
+        Map<String, Object> attrs = getNamespaceAttributes(resource, "osgi.content");
+        if (attrs == null)
+            return null;
+        return (String) attrs.get("mime");
+    }
+
+    public static String getSHA(Resource resource) {
+        Map<String, Object> attrs = getNamespaceAttributes(resource, "osgi.content");
+        if (attrs == null)
+            return null;
+        return (String) attrs.get("osgi.content");
+    }
+
+    public static boolean isSameBaseVersion(Version left, Version right) {
+        return left.getMajor() == right.getMajor() && left.getMinor() == right.getMinor() && left.getMicro() == right.getMicro();
+    }
+
+    private static Map<String, Object> getNamespaceAttributes(Resource resource, String namespace) {
+        List<Capability> caps = resource.getCapabilities(namespace);
+        if (caps.isEmpty())
+            return null;
+        Map<String, Object> attrs = caps.get(0).getAttributes();
+        if (attrs == null)
+            return null;
+        return attrs;
+    }
+
+    private static String getSnapshotQualifier(String prefix, int i) {
+        if (!isEmpty(prefix)) {
+            prefix = prefix + "_";
+        }
+        else {
+            prefix = "";
+        }
+        if (i < 10) {
+            return prefix + QUALIFIER_PREFIX + "00" + i;
+        }
+        else if (i < 100) {
+            return prefix + QUALIFIER_PREFIX + "0" + i;
+        }
+        else if (i < 1000) {
+            return prefix + QUALIFIER_PREFIX + i;
+        }
+        else {
+            throw new IllegalArgumentException("Can not qualifiers above 999");
+        }
+    }
+
+    private static boolean isEmpty(String s) {
+        return s == null || s.equals("");
+    }
+
+    private DeployerUtil() {
+    }
+}

Modified: ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/repository/AceObrRepository.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/repository/AceObrRepository.java?rev=1496021&r1=1496020&r2=1496021&view=diff
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/repository/AceObrRepository.java (original)
+++ ace/sandbox/bramk/org.apache.ace.cli/src/org/apache/ace/cli/repository/AceObrRepository.java Mon Jun 24 13:12:50 2013
@@ -98,6 +98,7 @@ public class AceObrRepository extends Fi
             }
             else {
                 // We need a mimetype or Jetty will throw a 500 Form too large
+
                 connection.setRequestProperty("Content-Type", "application/octet-stream");
             }
 
@@ -133,7 +134,7 @@ public class AceObrRepository extends Fi
             }
         }
         catch (IOException e) {
-            throw new IOException("Error importing resource: " + e.getMessage());
+            throw new IOException("Error importing resource: " + e.getMessage(), e);
         }
         finally {
             if (output != null) {

Added: ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/ContinuousDeployerTest.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/ContinuousDeployerTest.java?rev=1496021&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/ContinuousDeployerTest.java (added)
+++ ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/ContinuousDeployerTest.java Mon Jun 24 13:12:50 2013
@@ -0,0 +1,189 @@
+package org.apache.ace.cli.deployment;
+
+import static org.apache.ace.cli.deployment.DeployerUtil.copyResources;
+import static org.apache.ace.cli.deployment.DeployerUtil.findResources;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.jar.JarFile;
+
+import junit.framework.TestCase;
+
+import org.osgi.framework.Constants;
+
+import aQute.bnd.deployer.repository.LocalIndexedRepo;
+import aQute.bnd.osgi.Builder;
+import aQute.bnd.osgi.Jar;
+import aQute.bnd.service.Strategy;
+
+public class ContinuousDeployerTest extends TestCase {
+
+    File m_workDir;
+    LocalIndexedRepo m_developmentRepo;
+    LocalIndexedRepo m_releaseRepo;
+    LocalIndexedRepo m_deploymentRepo;
+    ContinuousDeployer m_deployer;
+
+    public void setUp() throws Exception {
+        m_workDir = new File("generated/cdtest-" + System.currentTimeMillis());
+        m_workDir.mkdir();
+        m_developmentRepo = createRepo(new File(m_workDir, "development"), "development");
+        m_deploymentRepo = createRepo(new File(m_workDir, "deployment"), "deployment");
+        m_releaseRepo = createRepo(new File(m_workDir, "release"), "release");
+        m_deployer = new ContinuousDeployer(m_deploymentRepo, m_developmentRepo, m_releaseRepo);
+    }
+
+    public void testInitialReleaseDeployment() throws Exception {
+
+        // an initial released bundle from development
+        m_developmentRepo.put(generateBundle("foo.bar", "1.0.0"), null);
+        copyResources(m_developmentRepo, m_releaseRepo, "foo.bar", "1.0.0");
+
+        // should have receive the correct release version
+        m_deployer.deployResources();
+        assertEquals(1, findResources(m_deploymentRepo, "foo.bar", "1.0.0").size());
+
+        // re-deploy of unchanged bundle should not affect the state
+        m_deployer.deployResources();
+        assertEquals(1, findResources(m_deploymentRepo, "foo.bar", "1.0.0").size());
+    }
+
+    public void testInitialSnapshotDeployment() throws Exception {
+
+        // an initial unreleased bundle from development
+        deployBundle(m_developmentRepo, createBundle("foo.bar", "1.0.0"));
+        Thread.sleep(100);
+
+        // should have receive the correct snapshot version
+        m_deployer.deployResources();
+        assertEquals(1, findResources(m_deploymentRepo, "foo.bar", "0.0.0.CDS000").size());
+
+        // re-deploy of unchanged bundle should not affect the state
+        m_deployer.deployResources();
+        assertEquals(1, findResources(m_deploymentRepo, "foo.bar", "0.0.0.CDS000").size());
+
+        // re-deploy of changed bundle should increment snapshot
+
+        // FIXME bug start
+
+        // create a new bundle and list manifest
+        File update = createBundle("foo.bar", "1.0.0", Constants.BUNDLE_COPYRIGHT, "Bundle 1", "bla", "bla");
+        listManifest(update);
+
+        // deploy, retrieve and list manifest
+        deployBundle(m_developmentRepo, update);
+        File check = m_developmentRepo.get("foo.bar", "1.0.0", Strategy.EXACT, null);
+        listManifest(check);
+
+        // Why do these manifest differ??? Unless in debug... there is a race condition in the BND IO?
+
+        // FIXME bug end
+
+        m_deployer.deployResources();
+
+        // assertEquals(1, findResources(m_deploymentRepo, "foo.bar", "0.0.0.CDS000").size());
+        assertEquals(1, findResources(m_deploymentRepo, "foo.bar", "0.0.0.CDS001").size());
+    }
+
+    private LocalIndexedRepo createRepo(File root, String name) throws Exception {
+        if (!(root.exists() || root.mkdir()) || !root.isDirectory())
+            throw new Exception("Can not access root: " + root.getAbsolutePath());
+        Map<String, String> props = new HashMap<String, String>();
+        props.put(LocalIndexedRepo.PROP_LOCAL_DIR, root.getAbsolutePath());
+        props.put(LocalIndexedRepo.PROP_PRETTY, "true");
+        props.put(LocalIndexedRepo.PROP_OVERWRITE, "true");
+        LocalIndexedRepo repo = new LocalIndexedRepo();
+        repo.setProperties(props);
+        return repo;
+    }
+
+    private void deployBundle(LocalIndexedRepo repo, InputStream stream) throws Exception {
+        try {
+            repo.put(stream, null);
+            stream.close();
+        }
+        finally {
+            stream.close();
+        }
+    }
+
+    private void deployBundle(LocalIndexedRepo repo, File file) throws Exception {
+        deployBundle(repo, new FileInputStream(file));
+    }
+
+    private void listManifest(File file) throws Exception {
+        JarFile j = new JarFile(file);
+        System.out.println("--------------------------");
+        System.out.println("Manifest for " + file.getAbsolutePath());
+        System.out.println("--------------------------");
+        for (Entry<Object, Object> entry : j.getManifest().getMainAttributes().entrySet()) {
+            System.out.println(" " + entry.getKey() + ": " + entry.getValue());
+        }
+        j.close();
+        System.out.println("--------------------------");
+
+    }
+
+    private InputStream generateBundle(final String bsn, final String version, final String... headers) throws Exception {
+        final PipedInputStream in = new PipedInputStream();
+        final PipedOutputStream out = new PipedOutputStream(in);
+        new Thread(
+            new Runnable() {
+                public void run() {
+                    Builder b = new Builder();
+                    try {
+                        b.setBundleSymbolicName(bsn);
+                        b.setBundleVersion(version);
+                        for (int i = 0; i < headers.length; i += 2) {
+                            b.setProperty(headers[i], headers[i + 1]);
+                        }
+                        b.setProperty("-noextraheaders", "true");
+                        Jar jar = b.build();
+                        jar.getManifest(); // Not sure whether this is needed...
+                        jar.write(out);
+                        out.flush();
+                        out.close();
+                        jar.close();
+                    }
+                    catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    finally {
+                        b.close();
+                    }
+                }
+            }).start();
+        return in;
+    }
+
+    private File createBundle(final String bsn, final String version, final String... headers) throws Exception {
+        Builder b = new Builder();
+        try {
+            b.setBundleSymbolicName(bsn);
+            b.setBundleVersion(version);
+            for (int i = 0; i < headers.length; i += 2) {
+                b.setProperty(headers[i], headers[i + 1]);
+            }
+            b.setProperty("-noextraheaders", "true");
+            Jar jar = b.build();
+            jar.getManifest(); // Not sure whether this is needed...
+            File tmp = File.createTempFile("tmpbundle", ".jar");
+            jar.write(tmp);
+            jar.close();
+            return tmp;
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+            throw e;
+        }
+        finally {
+            b.close();
+        }
+    }
+}

Added: ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/DeployerUtilTest.java
URL: http://svn.apache.org/viewvc/ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/DeployerUtilTest.java?rev=1496021&view=auto
==============================================================================
--- ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/DeployerUtilTest.java (added)
+++ ace/sandbox/bramk/org.apache.ace.cli/test/org/apache/ace/cli/deployment/DeployerUtilTest.java Mon Jun 24 13:12:50 2013
@@ -0,0 +1,25 @@
+package org.apache.ace.cli.deployment;
+
+import static org.apache.ace.cli.deployment.DeployerUtil.QUALIFIER_PREFIX;
+import static org.apache.ace.cli.deployment.DeployerUtil.getNextSnapshotVersion;
+import static org.osgi.framework.Version.parseVersion;
+import junit.framework.TestCase;
+
+public class DeployerUtilTest extends TestCase {
+
+    public void testFirstSnapshotNoQualifier() throws Exception {
+        assertEquals(parseVersion("1.0.0." + QUALIFIER_PREFIX + "000"), getNextSnapshotVersion(parseVersion("1.0.0")));
+    }
+
+    public void testFirstSnapshotQualifier() throws Exception {
+        assertEquals(parseVersion("1.0.0.RC_" + QUALIFIER_PREFIX + "000"), getNextSnapshotVersion(parseVersion("1.0.0.RC")));
+    }
+
+    public void testSecondSnapshotNoQualifier() throws Exception {
+        assertEquals(parseVersion("1.0.0." + QUALIFIER_PREFIX + "001"), getNextSnapshotVersion(parseVersion("1.0.0." + QUALIFIER_PREFIX + "000")));
+    }
+
+    public void testSecondSnapshotQualifier() throws Exception {
+        assertEquals(parseVersion("1.0.0.RC_" + QUALIFIER_PREFIX + "001"), getNextSnapshotVersion(parseVersion("1.0.0.RC_" + QUALIFIER_PREFIX + "000")));
+    }
+}