killbill-aplcache

osgi: be smarter when installing bundles * Don't install/start

3/1/2013 3:23:14 PM

Details

diff --git a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java
index e1ea4b7..5c0aa07 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java
@@ -18,17 +18,13 @@ package com.ning.billing.osgi;
 
 import java.io.File;
 import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 
 import javax.inject.Inject;
 
 import org.apache.felix.framework.Felix;
 import org.apache.felix.framework.util.FelixConstants;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.launch.Framework;
 import org.slf4j.Logger;
@@ -38,10 +34,6 @@ import com.ning.billing.lifecycle.LifecycleHandlerType;
 import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
 import com.ning.billing.osgi.api.OSGIService;
 import com.ning.billing.osgi.api.config.PluginConfigServiceApi;
-import com.ning.billing.osgi.api.config.PluginJavaConfig;
-import com.ning.billing.osgi.api.config.PluginRubyConfig;
-import com.ning.billing.osgi.pluginconf.DefaultPluginConfigServiceApi;
-import com.ning.billing.osgi.pluginconf.PluginConfigException;
 import com.ning.billing.osgi.pluginconf.PluginFinder;
 import com.ning.billing.util.config.OSGIConfig;
 
@@ -54,10 +46,8 @@ public class DefaultOSGIService implements OSGIService {
     private static final Logger logger = LoggerFactory.getLogger(DefaultOSGIService.class);
 
     private final OSGIConfig osgiConfig;
-    private final PureOSGIBundleFinder osgiBundleFinder;
-    private final PluginFinder pluginFinder;
-    private final PluginConfigServiceApi pluginConfigServiceApi;
     private final KillbillActivator killbillActivator;
+    private final FileInstall fileInstall;
 
     private Framework framework;
 
@@ -66,10 +56,8 @@ public class DefaultOSGIService implements OSGIService {
                               final PluginFinder pluginFinder, final PluginConfigServiceApi pluginConfigServiceApi,
                               final KillbillActivator killbillActivator) {
         this.osgiConfig = osgiConfig;
-        this.osgiBundleFinder = osgiBundleFinder;
-        this.pluginFinder = pluginFinder;
-        this.pluginConfigServiceApi = pluginConfigServiceApi;
         this.killbillActivator = killbillActivator;
+        this.fileInstall = new FileInstall(osgiBundleFinder, pluginFinder, pluginConfigServiceApi);
         this.framework = null;
     }
 
@@ -89,7 +77,7 @@ public class DefaultOSGIService implements OSGIService {
             framework.start();
 
             // This will call the start() method for the bundles
-            installAndStartBundles(framework);
+            fileInstall.installAndStartBundles(framework);
         } catch (BundleException e) {
             logger.error("Failed to initialize Killbill OSGIService", e);
         }
@@ -120,78 +108,6 @@ public class DefaultOSGIService implements OSGIService {
         }
     }
 
-    private void installAndStartBundles(final Framework framework) {
-        try {
-            final BundleContext context = framework.getBundleContext();
-
-            // Install all bundles and create service mapping
-
-            final List<Bundle> installedBundles = new LinkedList<Bundle>();
-            installAllJavaBundles(context, installedBundles);
-            installAllJavaPluginBundles(context, installedBundles);
-            installAllJRubyPluginBundles(context, installedBundles);
-
-            // Start all the bundles
-            for (final Bundle bundle : installedBundles) {
-                logger.info("Starting bundle {}", bundle.getLocation());
-                try {
-                    bundle.start();
-                } catch (BundleException e) {
-                    // TODO PIERRE Don't try to start Fragment bundles
-                    logger.warn("Unable to start bundle", e);
-                }
-            }
-        } catch (PluginConfigException e) {
-            logger.error("Error while parsing plugin configurations", e);
-        } catch (BundleException e) {
-            logger.error("Error while parsing plugin configurations", e);
-        }
-    }
-
-    private void installAllJavaBundles(final BundleContext context, final List<Bundle> installedBundles) throws PluginConfigException, BundleException {
-        final List<String> bundleJarPaths = osgiBundleFinder.getLatestBundles();
-        for (final String cur : bundleJarPaths) {
-            logger.info("Installing Java OSGI bundle in {}", cur);
-            final Bundle bundle = context.installBundle("file:" + cur);
-            installedBundles.add(bundle);
-        }
-    }
-
-    private void installAllJavaPluginBundles(final BundleContext context, final List<Bundle> installedBundles) throws PluginConfigException, BundleException {
-        final List<PluginJavaConfig> pluginJavaConfigs = pluginFinder.getLatestJavaPlugins();
-        for (final PluginJavaConfig cur : pluginJavaConfigs) {
-            logger.info("Installing Java bundle for plugin {} in {}", cur.getPluginName(), cur.getBundleJarPath());
-            final Bundle bundle = context.installBundle("file:" + cur.getBundleJarPath());
-            ((DefaultPluginConfigServiceApi) pluginConfigServiceApi).registerBundle(bundle.getBundleId(), cur);
-            installedBundles.add(bundle);
-        }
-    }
-
-    private void installAllJRubyPluginBundles(final BundleContext context, final List<Bundle> installedBundles) throws PluginConfigException, BundleException {
-        final String jrubyBundlePath = findJrubyBundlePath();
-        if (jrubyBundlePath == null) {
-            return;
-        }
-
-        final List<PluginRubyConfig> pluginRubyConfigs = pluginFinder.getLatestRubyPlugins();
-        for (final PluginRubyConfig cur : pluginRubyConfigs) {
-            logger.info("Installing JRuby bundle for plugin {} in {}", cur.getPluginName(), cur.getRubyLoadDir());
-            final Bundle bundle = context.installBundle("file:" + jrubyBundlePath);
-            ((DefaultPluginConfigServiceApi) pluginConfigServiceApi).registerBundle(bundle.getBundleId(), cur);
-            installedBundles.add(bundle);
-        }
-    }
-
-    private String findJrubyBundlePath() {
-        final String expectedPath = osgiBundleFinder.getPlatformOSGIBundlesRootDir() + "jruby.jar";
-        if (new File(expectedPath).isFile()) {
-            return expectedPath;
-        } else {
-            logger.warn("Unable to find the JRuby bundle for ruby plugins. If you want to install ruby plugins, copy the jar to " + expectedPath);
-            return null;
-        }
-    }
-
     private Framework createAndInitFramework() throws BundleException {
         final Map<String, String> config = new HashMap<String, String>();
         config.put("org.osgi.framework.system.packages.extra", osgiConfig.getSystemBundleExportPackages());
diff --git a/osgi/src/main/java/com/ning/billing/osgi/FileInstall.java b/osgi/src/main/java/com/ning/billing/osgi/FileInstall.java
new file mode 100644
index 0000000..d6138da
--- /dev/null
+++ b/osgi/src/main/java/com/ning/billing/osgi/FileInstall.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.osgi;
+
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.wiring.BundleRevision;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.osgi.api.config.PluginConfigServiceApi;
+import com.ning.billing.osgi.api.config.PluginJavaConfig;
+import com.ning.billing.osgi.api.config.PluginRubyConfig;
+import com.ning.billing.osgi.pluginconf.DefaultPluginConfigServiceApi;
+import com.ning.billing.osgi.pluginconf.PluginConfigException;
+import com.ning.billing.osgi.pluginconf.PluginFinder;
+
+// TODO Pierre Should we leverage org.apache.felix.fileinstall.internal.FileInstall?
+public class FileInstall {
+
+    private static final Logger logger = LoggerFactory.getLogger(FileInstall.class);
+
+    private final PureOSGIBundleFinder osgiBundleFinder;
+    private final PluginFinder pluginFinder;
+    private final PluginConfigServiceApi pluginConfigServiceApi;
+
+    public FileInstall(final PureOSGIBundleFinder osgiBundleFinder, final PluginFinder pluginFinder, final PluginConfigServiceApi pluginConfigServiceApi) {
+        this.osgiBundleFinder = osgiBundleFinder;
+        this.pluginFinder = pluginFinder;
+        this.pluginConfigServiceApi = pluginConfigServiceApi;
+    }
+
+    public void installAndStartBundles(final Framework framework) {
+        try {
+            final BundleContext context = framework.getBundleContext();
+
+            final String jrubyBundlePath = findJrubyBundlePath();
+
+            // Install all bundles and create service mapping
+            final List<Bundle> installedBundles = new LinkedList<Bundle>();
+            installAllJavaBundles(context, installedBundles, jrubyBundlePath);
+            installAllJavaPluginBundles(context, installedBundles);
+            installAllJRubyPluginBundles(context, installedBundles, jrubyBundlePath);
+
+            // Start all the bundles
+            for (final Bundle bundle : installedBundles) {
+                startBundle(bundle);
+            }
+        } catch (PluginConfigException e) {
+            logger.error("Error while parsing plugin configurations", e);
+        } catch (BundleException e) {
+            logger.error("Error while parsing plugin configurations", e);
+        }
+    }
+
+    private void installAllJavaBundles(final BundleContext context, final List<Bundle> installedBundles, @Nullable final String jrubyBundlePath) throws PluginConfigException, BundleException {
+        final List<String> bundleJarPaths = osgiBundleFinder.getLatestBundles();
+        for (final String cur : bundleJarPaths) {
+            // Don't install the jruby.jar bundle
+            if (jrubyBundlePath != null && jrubyBundlePath.equals(cur)) {
+                continue;
+            }
+
+            logger.info("Installing Java OSGI bundle from {}", cur);
+            final Bundle bundle = context.installBundle("file:" + cur);
+            installedBundles.add(bundle);
+        }
+    }
+
+    private void installAllJavaPluginBundles(final BundleContext context, final List<Bundle> installedBundles) throws PluginConfigException, BundleException {
+        final List<PluginJavaConfig> pluginJavaConfigs = pluginFinder.getLatestJavaPlugins();
+        for (final PluginJavaConfig cur : pluginJavaConfigs) {
+            logger.info("Installing Java bundle for plugin {} from {}", cur.getPluginName(), cur.getBundleJarPath());
+            final Bundle bundle = context.installBundle("file:" + cur.getBundleJarPath());
+            ((DefaultPluginConfigServiceApi) pluginConfigServiceApi).registerBundle(bundle.getBundleId(), cur);
+            installedBundles.add(bundle);
+        }
+    }
+
+    private void installAllJRubyPluginBundles(final BundleContext context, final List<Bundle> installedBundles, @Nullable final String jrubyBundlePath) throws PluginConfigException, BundleException {
+        if (jrubyBundlePath == null) {
+            return;
+        }
+
+        final List<PluginRubyConfig> pluginRubyConfigs = pluginFinder.getLatestRubyPlugins();
+        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);
+        }
+    }
+
+    private String findJrubyBundlePath() {
+        final String expectedPath = osgiBundleFinder.getPlatformOSGIBundlesRootDir() + "jruby.jar";
+        if (new File(expectedPath).isFile()) {
+            return expectedPath;
+        } else {
+            logger.warn("Unable to find the JRuby bundle for ruby plugins. If you want to install ruby plugins, copy the jar to " + expectedPath);
+            return null;
+        }
+    }
+
+    private boolean startBundle(final Bundle bundle) {
+        if (bundle.getState() == Bundle.UNINSTALLED) {
+            logger.info("Skipping uninstalled bundle {}", bundle.getLocation());
+        } else if (isFragment(bundle)) {
+            // Fragments can never be started.
+            logger.info("Skipping fragment bundle {}", bundle.getLocation());
+        } else {
+            logger.info("Starting bundle {}", bundle.getLocation());
+            try {
+                bundle.start();
+                return true;
+            } catch (BundleException e) {
+                logger.warn("Unable to start bundle", e);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Check if a bundle is a fragment.
+     *
+     * @param bundle bundle to check
+     * @return true iff the bundle is a fragment
+     */
+    private boolean isFragment(final Bundle bundle) {
+        // Necessary cast on jdk7
+        final BundleRevision bundleRevision = (BundleRevision) bundle.adapt(BundleRevision.class);
+        return bundleRevision != null && (bundleRevision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0;
+    }
+}