Author: bdelacretaz
Date: Mon Dec 21 15:11:26 2015
New Revision: 1721185

URL: http://svn.apache.org/viewvc?rev=1721185&view=rev
Log:
SLING-5379 - support renaming of bundles in maven-slingstart-plugin. 
Contributed by David Bosschaert, thanks!

Added:
    
sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/BundleUtil.java
    
sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/BundleUtilTest.java
Modified:
    sling/trunk/bundles/commons/osgi/pom.xml
    
sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/package-info.java
    sling/trunk/tooling/maven/slingstart-maven-plugin/pom.xml
    
sling/trunk/tooling/maven/slingstart-maven-plugin/src/main/java/org/apache/sling/maven/slingstart/PreparePackageMojo.java
    
sling/trunk/tooling/maven/slingstart-maven-plugin/src/test/java/org/apache/sling/maven/slingstart/PreparePackageMojoTest.java

Modified: sling/trunk/bundles/commons/osgi/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/commons/osgi/pom.xml?rev=1721185&r1=1721184&r2=1721185&view=diff
==============================================================================
--- sling/trunk/bundles/commons/osgi/pom.xml (original)
+++ sling/trunk/bundles/commons/osgi/pom.xml Mon Dec 21 15:11:26 2015
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.commons.osgi</artifactId>
-    <version>2.3.1-SNAPSHOT</version>
+    <version>2.3.1-SNAPSHOT</version> <!-- next release version should be 2.4 
given new BundleUtil -->
     <packaging>bundle</packaging>
 
     <name>Apache Sling Commons OSGi support</name>
@@ -41,6 +41,7 @@
     </scm>
     
     <properties>
+        <sling.java.version>7</sling.java.version>
         
<test.jars.folder>${project.build.directory}/testjars</test.jars.folder>
     </properties>
 

Added: 
sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/BundleUtil.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/BundleUtil.java?rev=1721185&view=auto
==============================================================================
--- 
sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/BundleUtil.java
 (added)
+++ 
sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/BundleUtil.java
 Mon Dec 21 15:11:26 2015
@@ -0,0 +1,103 @@
+/*
+ * 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.sling.commons.osgi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+/**
+ * The <code>BundleUtil</code> is a utility class providing some
+ * useful utility methods for bundle handling.
+ * @since 2.4
+ */
+public class BundleUtil {
+    /**
+     * Creates a new OSGi Bundle from a given bundle with the only difference 
that the
+     * symbolic name is changed. The original symbolic name is recorded in the 
Manifest
+     * using the {@code X-Original-Bundle-SymbolicName} header.
+     * @param bundleFile The original bundle file. This file will not be 
modified.
+     * @param newBSN The new Bundle-SymbolicName
+     * @param tempDir The temporary directory to use. This is where the new 
bundle will be
+     * written. This directory must exist.
+     * @return The new bundle with the altered Symbolic Name.
+     * @throws IOException If something goes wrong reading or writing.
+     */
+    public static File renameBSN(File bundleFile, String newBSN, File tempDir) 
throws IOException {
+        try (JarInputStream jis = new JarInputStream(new 
FileInputStream(bundleFile))) {
+            Manifest inputMF = jis.getManifest();
+
+            Attributes inputAttrs = inputMF.getMainAttributes();
+            String bver = inputAttrs.getValue("Bundle-Version");
+            String orgBSN = inputAttrs.getValue("Bundle-SymbolicName");
+            if (bver == null)
+                bver = "0.0.0";
+
+            File newBundle = new File(tempDir, newBSN + "-" + bver + ".jar");
+
+            Manifest newMF = new Manifest(inputMF);
+            Attributes outputAttrs = newMF.getMainAttributes();
+            outputAttrs.putValue("Bundle-SymbolicName", newBSN);
+            outputAttrs.putValue("X-Original-Bundle-SymbolicName", orgBSN);
+
+            try (JarOutputStream jos = new JarOutputStream(new 
FileOutputStream(newBundle), newMF)) {
+                JarEntry je = null;
+                while ((je = jis.getNextJarEntry()) != null) {
+                    try {
+                        jos.putNextEntry(je);
+                        if (!je.isDirectory())
+                            pumpStream(jis, jos);
+                    } finally {
+                        jos.closeEntry();
+                        jis.closeEntry();;
+                    }
+                }
+            }
+
+            return newBundle;
+        }
+    }
+
+    static void pumpStream(InputStream is, OutputStream os) throws IOException 
{
+        byte[] bytes = new byte[65536];
+
+        int length = 0;
+        int offset = 0;
+
+        while ((length = is.read(bytes, offset, bytes.length - offset)) != -1) 
{
+            offset += length;
+
+            if (offset == bytes.length) {
+                os.write(bytes, 0, bytes.length);
+                offset = 0;
+            }
+        }
+        if (offset != 0) {
+            os.write(bytes, 0, offset);
+        }
+    }
+}

Modified: 
sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/package-info.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/package-info.java?rev=1721185&r1=1721184&r2=1721185&view=diff
==============================================================================
--- 
sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/package-info.java
 (original)
+++ 
sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/package-info.java
 Mon Dec 21 15:11:26 2015
@@ -16,5 +16,5 @@
  * specific language governing permissions and limitations
  * under the License.
  */
[email protected]("2.3")
[email protected]("2.4")
 package org.apache.sling.commons.osgi;

Added: 
sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/BundleUtilTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/BundleUtilTest.java?rev=1721185&view=auto
==============================================================================
--- 
sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/BundleUtilTest.java
 (added)
+++ 
sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/BundleUtilTest.java
 Mon Dec 21 15:11:26 2015
@@ -0,0 +1,133 @@
+/*
+ * 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.sling.commons.osgi;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class BundleUtilTest {
+    @Test
+    public void testBSNRenaming() throws IOException {
+        File tempDir = new File(System.getProperty("java.io.tmpdir"));
+
+        // Just take any bundle from the maven deps as an example...
+        File originalFile = getMavenArtifactFile(getMavenRepoRoot(), 
"com.google.guava", "guava", "15.0");
+
+        File generatedFile = BundleUtil.renameBSN(originalFile, 
"org.acme.baklava.guava", tempDir);
+
+        try {
+            compareJarContents(originalFile, generatedFile);
+
+            try (JarFile jfOrg = new JarFile(originalFile);
+                    JarFile jfNew = new JarFile(generatedFile)) {
+                    Manifest mfOrg = jfOrg.getManifest();
+                    Manifest mfNew = jfNew.getManifest();
+
+                    Attributes orgAttrs = mfOrg.getMainAttributes();
+                    Attributes newAttrs = mfNew.getMainAttributes();
+                    for (Object key : orgAttrs.keySet()) {
+                        String orgVal = orgAttrs.getValue(key.toString());
+                        String newVal = newAttrs.getValue(key.toString());
+
+                        if ("Bundle-SymbolicName".equals(key.toString())) {
+                            assertEquals("Should have recorded the original 
Bundle-SymbolicName",
+                                    orgVal, 
newAttrs.getValue("X-Original-Bundle-SymbolicName"));
+
+                            assertEquals("org.acme.baklava.guava", newVal);
+                        } else {
+                            assertEquals("Different keys: " + key, orgVal, 
newVal);
+                        }
+                    }
+                }
+
+        } finally {
+            assertTrue("Unable to delete temporary file", 
generatedFile.delete());
+        }
+    }
+
+    private static void compareJarContents(File orgJar, File actualJar) throws 
IOException {
+        try (JarInputStream jis1 = new JarInputStream(new 
FileInputStream(orgJar));
+            JarInputStream jis2 = new JarInputStream(new 
FileInputStream(actualJar))) {
+            JarEntry je1 = null;
+            while ((je1 = jis1.getNextJarEntry()) != null) {
+                if (je1.isDirectory())
+                    continue;
+
+                JarEntry je2 = null;
+                while((je2 = jis2.getNextJarEntry()) != null) {
+                    if (!je2.isDirectory())
+                        break;
+                }
+
+                assertEquals(je1.getName(), je2.getName());
+                assertEquals(je1.getSize(), je2.getSize());
+
+                try {
+                    byte[] buf1 = streamToByteArray(jis1);
+                    byte[] buf2 = streamToByteArray(jis2);
+
+                    assertArrayEquals("Contents not equal: " + je1.getName(), 
buf1, buf2);
+                } finally {
+                    jis1.closeEntry();
+                    jis2.closeEntry();
+                }
+            }
+        }
+    }
+
+    private static byte [] streamToByteArray(InputStream is) throws 
IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        BundleUtil.pumpStream(is, baos);
+        return baos.toByteArray();
+    }
+
+    private static File getMavenArtifactFile(File repoRoot, String gid, String 
aid, String ver) {
+        return new File(repoRoot, gid.replace('.', '/') + '/' + aid + '/' + 
ver + '/' + aid + '-' + ver + ".jar");
+    }
+
+    private static File getMavenRepoRoot() throws IOException {
+        URL res = BundleUtilTest.class.getClassLoader().getResource(
+                Test.class.getName().replace('.', '/') + ".class");
+
+        String u = res.toExternalForm();
+        if (u.startsWith("jar:"))
+            u = u.substring(4);
+
+        int idx = u.indexOf("junit");
+        if (idx < 0)
+            throw new IllegalStateException("Cannot infer maven repo root: " + 
res);
+
+        return new File(new URL(u.substring(0, idx)).getFile());
+    }
+}

Modified: sling/trunk/tooling/maven/slingstart-maven-plugin/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/maven/slingstart-maven-plugin/pom.xml?rev=1721185&r1=1721184&r2=1721185&view=diff
==============================================================================
--- sling/trunk/tooling/maven/slingstart-maven-plugin/pom.xml (original)
+++ sling/trunk/tooling/maven/slingstart-maven-plugin/pom.xml Mon Dec 21 
15:11:26 2015
@@ -86,7 +86,7 @@
        <dependency>
            <groupId>org.apache.sling</groupId>
            <artifactId>org.apache.sling.provisioning.model</artifactId>
-           <version>1.4.0</version>
+           <version>1.4.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
@@ -169,6 +169,11 @@
             </exclusions>
         </dependency>
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.3.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-all</artifactId>
             <version>1.10.19</version>
@@ -207,12 +212,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.commons.osgi</artifactId>
-            <version>2.3.0</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.threads</artifactId>
             <version>3.2.0</version>

Modified: 
sling/trunk/tooling/maven/slingstart-maven-plugin/src/main/java/org/apache/sling/maven/slingstart/PreparePackageMojo.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/maven/slingstart-maven-plugin/src/main/java/org/apache/sling/maven/slingstart/PreparePackageMojo.java?rev=1721185&r1=1721184&r2=1721185&view=diff
==============================================================================
--- 
sling/trunk/tooling/maven/slingstart-maven-plugin/src/main/java/org/apache/sling/maven/slingstart/PreparePackageMojo.java
 (original)
+++ 
sling/trunk/tooling/maven/slingstart-maven-plugin/src/main/java/org/apache/sling/maven/slingstart/PreparePackageMojo.java
 Mon Dec 21 15:11:26 2015
@@ -48,6 +48,7 @@ import org.apache.maven.plugins.annotati
 import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.sling.commons.osgi.BundleUtil;
 import org.apache.sling.provisioning.model.ArtifactGroup;
 import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;
@@ -231,7 +232,18 @@ public class PreparePackageMojo extends
             for(final org.apache.sling.provisioning.model.Artifact a : group) {
                 final Artifact artifact = ModelUtils.getArtifact(this.project, 
this.mavenSession, this.artifactHandlerManager, this.resolver,
                         a.getGroupId(), a.getArtifactId(), a.getVersion(), 
a.getType(), a.getClassifier());
-                final File artifactFile = artifact.getFile();
+                File artifactFile = artifact.getFile();
+
+                String newBSN = a.getMetadata().get("bundle:rename-bsn");
+                if (newBSN != null) {
+                    try {
+                        getTmpDir().mkdirs();
+                        artifactFile = BundleUtil.renameBSN(artifactFile, 
newBSN, getTmpDir());
+                    } catch (IOException e) {
+                        throw new MojoExecutionException("Unable to rename 
bundle BSN to " + newBSN + " for " + artifactFile, e);
+                    }
+                }
+
                 contentsMap.put(getPathForArtifact(group.getStartLevel(), 
artifactFile.getName(), runMode, isBoot), artifactFile);
             }
         }
@@ -264,7 +276,6 @@ public class PreparePackageMojo extends
         }
     }
 
-
     private File createSubsystemBaseFile(Feature feature, AtomicInteger 
startLevelHolder) throws MojoExecutionException {
         File subsystemFile = new File(getTmpDir(), feature.getName() + 
".subsystem-base");
         if (subsystemFile.exists()) {
@@ -354,7 +365,7 @@ public class PreparePackageMojo extends
         attrs.putValue("Manifest-Version", "1.0"); // Manifest does not work 
without this value
         attrs.putValue("About-This-Manifest", "This is not a real manifest, it 
is used as information when this archive is transformed into a real subsystem 
.esa file");
         for (Map.Entry<String, StringBuilder> entry : runModes.entrySet()) {
-            attrs.putValue(entry.getKey(), entry.getValue().toString());
+            attrs.putValue(entry.getKey().replace(':', '_'), 
entry.getValue().toString());
         }
         return mf;
     }

Modified: 
sling/trunk/tooling/maven/slingstart-maven-plugin/src/test/java/org/apache/sling/maven/slingstart/PreparePackageMojoTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/maven/slingstart-maven-plugin/src/test/java/org/apache/sling/maven/slingstart/PreparePackageMojoTest.java?rev=1721185&r1=1721184&r2=1721185&view=diff
==============================================================================
--- 
sling/trunk/tooling/maven/slingstart-maven-plugin/src/test/java/org/apache/sling/maven/slingstart/PreparePackageMojoTest.java
 (original)
+++ 
sling/trunk/tooling/maven/slingstart-maven-plugin/src/test/java/org/apache/sling/maven/slingstart/PreparePackageMojoTest.java
 Mon Dec 21 15:11:26 2015
@@ -17,6 +17,7 @@
 package org.apache.sling.maven.slingstart;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringReader;
@@ -27,7 +28,9 @@ import java.nio.file.Path;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
 import java.util.jar.Manifest;
 import java.util.zip.ZipEntry;
 
@@ -52,7 +55,87 @@ import static org.junit.Assert.assertEqu
 
 public class PreparePackageMojoTest {
     @Test
-    public void testSubsystemBaseGeneration1() throws Exception {
+    public void testBSNRenaming() throws Exception {
+        // Provide the system with some artifacts that are known to be in the 
local .m2 repo
+        // These are explicitly included in the test section of the pom.xml
+        PreparePackageMojo ppm = getMojoUnderTest(
+                "org.apache.sling/org.apache.sling.commons.classloader/1.3.2",
+                
"org.apache.sling/org.apache.sling.commons.classloader/1.3.2/app",
+                "org.apache.sling/org.apache.sling.commons.json/2.0.12");
+        try {
+            String modelTxt = "[feature name=:launchpad]\n" +
+                    "[artifacts]\n" +
+                    "  
org.apache.sling/org.apache.sling.commons.classloader/1.3.2\n" +
+                    "" +
+                    "[feature name=rename_test]\n" +
+                    "  org.apache.sling/org.apache.sling.commons.json/2.0.12 
[bundle:rename-bsn=r-foo.bar.renamed.sling.commons.json]\n";
+
+            Model model = ModelReader.read(new StringReader(modelTxt), null);
+            ppm.execute(model);
+
+            File orgJar = getMavenArtifactFile(getMavenRepoRoot(), 
"org.apache.sling", "org.apache.sling.commons.json", "2.0.12");
+            File generatedJar = new File(ppm.getTmpDir() + 
"/r-foo.bar.renamed.sling.commons.json-2.0.12.jar");
+
+            compareJarContents(orgJar, generatedJar);
+
+            try (JarFile jfOrg = new JarFile(orgJar);
+                JarFile jfNew = new JarFile(generatedJar)) {
+                Manifest mfOrg = jfOrg.getManifest();
+                Manifest mfNew = jfNew.getManifest();
+
+                Attributes orgAttrs = mfOrg.getMainAttributes();
+                Attributes newAttrs = mfNew.getMainAttributes();
+                for (Object key : orgAttrs.keySet()) {
+                    String orgVal = orgAttrs.getValue(key.toString());
+                    String newVal = newAttrs.getValue(key.toString());
+
+                    if ("Bundle-SymbolicName".equals(key.toString())) {
+                        assertEquals("Should have recorded the original 
Bundle-SymbolicName",
+                                orgVal, 
newAttrs.getValue("X-Original-Bundle-SymbolicName"));
+
+                        assertEquals("r-foo.bar.renamed.sling.commons.json", 
newVal);
+                    } else {
+                        assertEquals("Different keys: " + key, orgVal, newVal);
+                    }
+                }
+            }
+        } finally {
+            FileUtils.deleteDirectory(new 
File(ppm.project.getBuild().getDirectory()));
+        }
+    }
+
+    private static void compareJarContents(File orgJar, File actualJar) throws 
IOException {
+        try (JarInputStream jis1 = new JarInputStream(new 
FileInputStream(orgJar));
+            JarInputStream jis2 = new JarInputStream(new 
FileInputStream(actualJar))) {
+            JarEntry je1 = null;
+            while ((je1 = jis1.getNextJarEntry()) != null) {
+                if (je1.isDirectory())
+                    continue;
+
+                JarEntry je2 = null;
+                while((je2 = jis2.getNextJarEntry()) != null) {
+                    if (!je2.isDirectory())
+                        break;
+                }
+
+                assertEquals(je1.getName(), je2.getName());
+                assertEquals(je1.getSize(), je2.getSize());
+
+                try {
+                    byte[] buf1 = IOUtils.toByteArray(jis1);
+                    byte[] buf2 = IOUtils.toByteArray(jis2);
+
+                    assertArrayEquals("Contents not equal: " + je1.getName(), 
buf1, buf2);
+                } finally {
+                    jis1.closeEntry();
+                    jis2.closeEntry();
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testSubsystemBaseGeneration() throws Exception {
         // Provide the system with some artifacts that are known to be in the 
local .m2 repo
         // These are explicitly included in the test section of the pom.xml
         PreparePackageMojo ppm = getMojoUnderTest(
@@ -84,7 +167,7 @@ public class PreparePackageMojoTest {
                     "  
org.apache.sling/org.apache.sling.commons.json/2.0.12\n" +
                     "  org.apache.sling/org.apache.sling.commons.mime/2.1.8\n" 
+
                     "" +
-                    "[artifacts startLevel=20 runModes=foo,bar]\n" +
+                    "[artifacts startLevel=20 runModes=foo,bar,:blah]\n" +
                     "  
org.apache.sling/org.apache.sling.commons.threads/3.2.0\n" +
                     "" +
                     "[artifacts startLevel=100 runModes=bar]\n" +


Reply via email to