killbill-memoizeit

Details

diff --git a/osgi/src/main/java/com/ning/billing/osgi/FileInstall.java b/osgi/src/main/java/com/ning/billing/osgi/FileInstall.java
index 51899a0..cc122c0 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/FileInstall.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/FileInstall.java
@@ -16,15 +16,30 @@
 
 package com.ning.billing.osgi;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
 
 import javax.annotation.Nullable;
 
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
 import org.osgi.framework.launch.Framework;
 import org.osgi.framework.wiring.BundleRevision;
 import org.slf4j.Logger;
@@ -37,6 +52,8 @@ import com.ning.billing.osgi.pluginconf.DefaultPluginConfigServiceApi;
 import com.ning.billing.osgi.pluginconf.PluginConfigException;
 import com.ning.billing.osgi.pluginconf.PluginFinder;
 
+import com.google.common.io.ByteStreams;
+
 // TODO Pierre Should we leverage org.apache.felix.fileinstall.internal.FileInstall?
 public class FileInstall {
 
@@ -105,12 +122,61 @@ public class FileInstall {
         }
 
         final List<PluginRubyConfig> pluginRubyConfigs = pluginFinder.getLatestRubyPlugins();
+        int i = 0;
         for (final PluginRubyConfig cur : pluginRubyConfigs) {
-            logger.info("Installing JRuby bundle for plugin {} from {}", cur.getPluginName(), cur.getRubyLoadDir());
-            final Bundle bundle = context.installBundle("file:" + jrubyBundlePath);
-            ((DefaultPluginConfigServiceApi) pluginConfigServiceApi).registerBundle(bundle.getBundleId(), cur);
-            installedBundles.add(bundle);
+
+            final String uniqueJrubyBundlePath = "jruby-" + cur.getPluginName();
+
+            InputStream tweakedInputStream = null;
+            try {
+                logger.info("Installing JRuby bundle for plugin {} ", uniqueJrubyBundlePath);
+                tweakedInputStream = tweakRubyManifestToBeUnique(jrubyBundlePath, ++i);
+                final Bundle bundle = context.installBundle(uniqueJrubyBundlePath, tweakedInputStream);
+                ((DefaultPluginConfigServiceApi) pluginConfigServiceApi).registerBundle(bundle.getBundleId(), cur);
+                installedBundles.add(bundle);
+            } catch (IOException e) {
+                logger.warn("Failed to open file {}", jrubyBundlePath);
+            } finally {
+                if (tweakedInputStream != null) {
+                    try {
+                        tweakedInputStream.close();
+                    } catch (IOException ignore) {
+                    }
+                }
+            }
+        }
+    }
+
+
+    private InputStream tweakRubyManifestToBeUnique(final String rubyJar, int index) throws IOException {
+
+        final Attributes.Name attrName = new Attributes.Name(Constants.BUNDLE_SYMBOLICNAME);
+        final JarInputStream in = new JarInputStream(new FileInputStream(new File(rubyJar)));
+        final Manifest manifest = in.getManifest();
+
+
+        final Object currentValue = manifest.getMainAttributes().get(attrName);
+        manifest.getMainAttributes().put(attrName, currentValue.toString() + "-" + index);
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        final JarOutputStream jarOut = new JarOutputStream(out, manifest);
+        try {
+            JarEntry e = in.getNextJarEntry();
+            while (e != null) {
+                if (!e.getName().equals(JarFile.MANIFEST_NAME)) {
+                    jarOut.putNextEntry(e);
+                    ByteStreams.copy(in, jarOut);
+                }
+                e = in.getNextJarEntry();
+            }
+
+        } finally {
+            if (jarOut != null) {
+                jarOut.close();
+            }
         }
+
+        return new ByteArrayInputStream(out.toByteArray());
     }
 
     private String findJrubyBundlePath() {