killbill-uncached

jruby: don't attempt to start the plugin until OSGIKillbill

4/14/2014 5:41:17 PM

Details

diff --git a/osgi-bundles/bundles/jruby/src/main/java/org/killbill/billing/osgi/bundles/jruby/JRubyActivator.java b/osgi-bundles/bundles/jruby/src/main/java/org/killbill/billing/osgi/bundles/jruby/JRubyActivator.java
index 569e265..5824a65 100644
--- a/osgi-bundles/bundles/jruby/src/main/java/org/killbill/billing/osgi/bundles/jruby/JRubyActivator.java
+++ b/osgi-bundles/bundles/jruby/src/main/java/org/killbill/billing/osgi/bundles/jruby/JRubyActivator.java
@@ -22,15 +22,16 @@ import java.util.Map;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
-import org.osgi.framework.BundleContext;
-import org.osgi.service.log.LogService;
-
-import org.killbill.commons.concurrent.Executors;
 import org.killbill.billing.osgi.api.config.PluginConfig.PluginType;
 import org.killbill.billing.osgi.api.config.PluginConfigServiceApi;
 import org.killbill.billing.osgi.api.config.PluginRubyConfig;
+import org.killbill.commons.concurrent.Executors;
 import org.killbill.killbill.osgi.libs.killbill.KillbillActivatorBase;
+import org.killbill.killbill.osgi.libs.killbill.KillbillServiceListener;
+import org.killbill.killbill.osgi.libs.killbill.KillbillServiceListenerCallback;
 import org.killbill.killbill.osgi.libs.killbill.OSGIKillbillEventDispatcher.OSGIKillbillEventHandler;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
 
 import com.google.common.base.Objects;
 
@@ -52,6 +53,22 @@ public class JRubyActivator extends KillbillActivatorBase {
     public void start(final BundleContext context) throws Exception {
         super.start(context);
 
+        final String osgiKillbillClass = "org.killbill.billing.osgi.api.OSGIKillbill";
+        final KillbillServiceListenerCallback listenerCallback = new KillbillServiceListenerCallback() {
+            @Override
+            public void isRegistered(final BundleContext context) {
+                startWithContextClassLoader(context);
+            }
+        };
+        KillbillServiceListener.listenForService(context, osgiKillbillClass, listenerCallback);
+    }
+
+    private void startWithContextClassLoader(final BundleContext context) {
+        if (restartFuture != null) {
+            // If the restart future is already configured, the plugin had already started
+            return;
+        }
+
         withContextClassLoader(new PluginCall() {
             @Override
             public void doCall() {
@@ -108,26 +125,26 @@ public class JRubyActivator extends KillbillActivatorBase {
 
         restartFuture = Executors.newSingleThreadScheduledExecutor("jruby-restarter-" + pluginMain)
                                  .scheduleWithFixedDelay(new Runnable() {
-            long lastRestartMillis = System.currentTimeMillis();
+                                     long lastRestartMillis = System.currentTimeMillis();
 
-            @Override
-            public void run() {
+                                     @Override
+                                     public void run() {
 
-                final File restartFile = new File(tmpDirPath + "/" + RESTART_FILE_NAME);
-                if (!restartFile.isFile()) {
-                    return;
-                }
+                                         final File restartFile = new File(tmpDirPath + "/" + RESTART_FILE_NAME);
+                                         if (!restartFile.isFile()) {
+                                             return;
+                                         }
 
-                if (restartFile.lastModified() > lastRestartMillis) {
-                    logService.log(LogService.LOG_INFO, "Restarting JRuby plugin " + rubyConfig.getRubyMainClass());
+                                         if (restartFile.lastModified() > lastRestartMillis) {
+                                             logService.log(LogService.LOG_INFO, "Restarting JRuby plugin " + rubyConfig.getRubyMainClass());
 
-                    doStopPlugin(context);
-                    doStartPlugin(pluginMain, context, killbillServices);
+                                             doStopPlugin(context);
+                                             doStartPlugin(pluginMain, context, killbillServices);
 
-                    lastRestartMillis = restartFile.lastModified();
-                }
-            }
-        }, JRUBY_PLUGINS_RESTART_DELAY_SECS, JRUBY_PLUGINS_RESTART_DELAY_SECS, TimeUnit.SECONDS);
+                                             lastRestartMillis = restartFile.lastModified();
+                                         }
+                                     }
+                                 }, JRUBY_PLUGINS_RESTART_DELAY_SECS, JRUBY_PLUGINS_RESTART_DELAY_SECS, TimeUnit.SECONDS);
     }
 
     private PluginRubyConfig retrievePluginRubyConfig(final BundleContext context) {
@@ -148,7 +165,7 @@ public class JRubyActivator extends KillbillActivatorBase {
         }, this.getClass().getClassLoader());
     }
 
-    private void  doStartPlugin(final String pluginMain, final BundleContext context, final Map<String, Object> killbillServices) {
+    private void doStartPlugin(final String pluginMain, final BundleContext context, final Map<String, Object> killbillServices) {
         logService.log(LogService.LOG_INFO, "Starting JRuby plugin " + pluginMain);
         plugin.instantiatePlugin(killbillServices, pluginMain);
         plugin.startPlugin(context);
@@ -186,7 +203,6 @@ public class JRubyActivator extends KillbillActivatorBase {
         return killbillUserApis;
     }
 
-
     private static interface PluginCall {
 
         public void doCall();
diff --git a/osgi-bundles/libs/killbill/src/main/java/org/killbill/killbill/osgi/libs/killbill/KillbillServiceListener.java b/osgi-bundles/libs/killbill/src/main/java/org/killbill/killbill/osgi/libs/killbill/KillbillServiceListener.java
new file mode 100644
index 0000000..9f1af06
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/org/killbill/killbill/osgi/libs/killbill/KillbillServiceListener.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.killbill.osgi.libs.killbill;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+public class KillbillServiceListener implements ServiceListener {
+
+    private final BundleContext context;
+    private final KillbillServiceListenerCallback killbillServiceListenerCallback;
+
+    public static KillbillServiceListener listenForService(final BundleContext context, final String serviceClass, final KillbillServiceListenerCallback listenerCallback) throws InvalidSyntaxException {
+        final String filter = "(objectclass=" + serviceClass + ")";
+
+        final KillbillServiceListener killbillServiceListener = new KillbillServiceListener(context, listenerCallback);
+        context.addServiceListener(killbillServiceListener, filter);
+
+        // If the service was already registered, manually construct a REGISTERED ServiceEvent
+        final ServiceReference[] serviceReferences = context.getServiceReferences((String) null, filter);
+        for (int i = 0; serviceReferences != null && i < serviceReferences.length; i++) {
+            killbillServiceListener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, serviceReferences[i]));
+        }
+
+        return killbillServiceListener;
+    }
+
+    public KillbillServiceListener(final BundleContext context, final KillbillServiceListenerCallback killbillServiceListenerCallback) {
+        this.context = context;
+        this.killbillServiceListenerCallback = killbillServiceListenerCallback;
+    }
+
+    @Override
+    public void serviceChanged(final ServiceEvent event) {
+        final ServiceReference serviceReference = event.getServiceReference();
+        if (serviceReference == null || serviceReference.getBundle() == null) {
+            return;
+        }
+
+        final BundleContext bundleContext = serviceReference.getBundle().getBundleContext();
+        if (bundleContext == null) {
+            return;
+        }
+
+        final Object service = bundleContext.getService(serviceReference);
+        if (service != null) {
+            if (event.getType() == ServiceEvent.REGISTERED) {
+                killbillServiceListenerCallback.isRegistered(context);
+            } else if (event.getType() == ServiceEvent.UNREGISTERING) {
+                killbillServiceListenerCallback.isUnRegistering(context);
+            }
+        }
+    }
+}
diff --git a/osgi-bundles/libs/killbill/src/main/java/org/killbill/killbill/osgi/libs/killbill/KillbillServiceListenerCallback.java b/osgi-bundles/libs/killbill/src/main/java/org/killbill/killbill/osgi/libs/killbill/KillbillServiceListenerCallback.java
new file mode 100644
index 0000000..1ae028e
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/org/killbill/killbill/osgi/libs/killbill/KillbillServiceListenerCallback.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.killbill.osgi.libs.killbill;
+
+import org.osgi.framework.BundleContext;
+
+public abstract class KillbillServiceListenerCallback {
+
+    public void isRegistered(final BundleContext context) {
+    }
+
+    public void isUnRegistering(final BundleContext context) {
+    }
+}