killbill-memoizeit

Add OSGIUserApi for liveTracker Fix OSGI pom issues Code

2/28/2013 9:35:51 PM

Details

diff --git a/api/src/main/java/com/ning/billing/osgi/api/LiveTrackerException.java b/api/src/main/java/com/ning/billing/osgi/api/LiveTrackerException.java
new file mode 100644
index 0000000..23eee3e
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/osgi/api/LiveTrackerException.java
@@ -0,0 +1,28 @@
+/*
+ * 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.api;
+
+public class LiveTrackerException extends Exception {
+
+    public LiveTrackerException(String msg) {
+        super(msg);
+    }
+
+    public LiveTrackerException(String msg, Throwable e) {
+        super(msg, e);
+    }
+}
diff --git a/api/src/main/java/com/ning/billing/osgi/api/OSGIUserApi.java b/api/src/main/java/com/ning/billing/osgi/api/OSGIUserApi.java
new file mode 100644
index 0000000..60067be
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/osgi/api/OSGIUserApi.java
@@ -0,0 +1,22 @@
+/*
+ * 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.api;
+
+public interface OSGIUserApi {
+
+    public <S> S getService(Class<S> serviceClass) throws LiveTrackerException;
+}
diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApiException.java b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApiException.java
index 91c106c..f9a2000 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApiException.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApiException.java
@@ -24,6 +24,12 @@ public class PaymentPluginApiException extends Exception {
     private final String errorType;
     private final String errorMessage;
 
+    public PaymentPluginApiException(final String msg, final Throwable e) {
+        super(msg, e);
+        errorMessage = msg;
+        errorType = e.getMessage();
+    }
+
     public PaymentPluginApiException(final String errorType, final String errorMessage) {
         this.errorMessage = errorMessage;
         this.errorType = errorType;
@@ -46,8 +52,12 @@ public class PaymentPluginApiException extends Exception {
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("PaymentPluginApiException");
-        sb.append("{errorMessage='").append(errorMessage).append('\'');
-        sb.append(", errorType='").append(errorType).append('\'');
+        if (errorMessage != null) {
+            sb.append("{errorMessage='").append(errorMessage).append('\'');
+        }
+        if (errorType != null) {
+            sb.append(", errorType='").append(errorType).append('\'');
+        }
         sb.append('}');
         return sb.toString();
     }
diff --git a/osgi/src/main/java/com/ning/billing/osgi/api/DefaultOSGIUserApi.java b/osgi/src/main/java/com/ning/billing/osgi/api/DefaultOSGIUserApi.java
new file mode 100644
index 0000000..be9050b
--- /dev/null
+++ b/osgi/src/main/java/com/ning/billing/osgi/api/DefaultOSGIUserApi.java
@@ -0,0 +1,36 @@
+/*
+ * 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.api;
+
+import javax.inject.Inject;
+
+import com.ning.billing.osgi.LiveTracker;
+
+public class DefaultOSGIUserApi implements OSGIUserApi {
+
+    private final LiveTracker liveTracker;
+
+    @Inject
+    public DefaultOSGIUserApi(LiveTracker liveTracker) {
+        this.liveTracker = liveTracker;
+    }
+
+    @Override
+    public <S> S getService(final Class<S> serviceClass) throws LiveTrackerException {
+        return liveTracker.getRegisteredOSGIService(serviceClass);
+    }
+}
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 15516d0..e1ea4b7 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java
@@ -112,6 +112,7 @@ public class DefaultOSGIService implements OSGIService {
         try {
             framework.stop();
             framework.waitForStop(0);
+
         } catch (BundleException e) {
             logger.error("Failed to Stop Killbill OSGIService " + e.getMessage());
         } catch (InterruptedException e) {
diff --git a/osgi/src/main/java/com/ning/billing/osgi/glue/DefaultOSGIModule.java b/osgi/src/main/java/com/ning/billing/osgi/glue/DefaultOSGIModule.java
index c793069..ce9b51e 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/glue/DefaultOSGIModule.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/glue/DefaultOSGIModule.java
@@ -27,10 +27,13 @@ import com.ning.billing.osgi.DefaultOSGIKillbill;
 import com.ning.billing.osgi.DefaultOSGIService;
 import com.ning.billing.osgi.KillbillActivator;
 import com.ning.billing.osgi.KillbillEventObservable;
+import com.ning.billing.osgi.LiveTracker;
 import com.ning.billing.osgi.PureOSGIBundleFinder;
+import com.ning.billing.osgi.api.DefaultOSGIUserApi;
 import com.ning.billing.osgi.api.OSGIKillbill;
 import com.ning.billing.osgi.api.OSGIService;
 import com.ning.billing.osgi.api.OSGIServiceRegistration;
+import com.ning.billing.osgi.api.OSGIUserApi;
 import com.ning.billing.osgi.api.config.PluginConfigServiceApi;
 import com.ning.billing.osgi.http.DefaultHttpService;
 import com.ning.billing.osgi.http.DefaultServletRouter;
@@ -72,6 +75,8 @@ public class DefaultOSGIModule extends AbstractModule {
 
         bind(OSGIService.class).to(DefaultOSGIService.class).asEagerSingleton();
 
+        bind(OSGIUserApi.class).to(DefaultOSGIUserApi.class).asEagerSingleton();
+        bind(LiveTracker.class).to(KillbillActivator.class).asEagerSingleton();
         bind(KillbillActivator.class).asEagerSingleton();
         bind(PureOSGIBundleFinder.class).asEagerSingleton();
         bind(PluginFinder.class).asEagerSingleton();
diff --git a/osgi/src/main/java/com/ning/billing/osgi/KillbillActivator.java b/osgi/src/main/java/com/ning/billing/osgi/KillbillActivator.java
index 715c120..2a242f2 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/KillbillActivator.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/KillbillActivator.java
@@ -17,8 +17,10 @@
 package com.ning.billing.osgi;
 
 import java.util.Dictionary;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
 import java.util.Observable;
 
 import javax.inject.Inject;
@@ -32,9 +34,11 @@ import org.osgi.framework.ServiceEvent;
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.HttpService;
+import org.osgi.util.tracker.ServiceTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.osgi.api.LiveTrackerException;
 import com.ning.billing.osgi.api.OSGIKillbill;
 import com.ning.billing.osgi.api.OSGIPluginProperties;
 import com.ning.billing.osgi.api.OSGIServiceDescriptor;
@@ -45,7 +49,7 @@ import com.ning.killbill.osgi.libs.killbill.OSGIKillbillRegistrar;
 
 import com.google.common.collect.ImmutableList;
 
-public class KillbillActivator implements BundleActivator, ServiceListener {
+public class KillbillActivator implements BundleActivator, ServiceListener, LiveTracker {
 
     // TODO : Is that ok for system bundle to use Killbill Logger or do we need to LoggerService like we do for any other bundle
     private final static Logger logger = LoggerFactory.getLogger(KillbillActivator.class);
@@ -55,6 +59,7 @@ public class KillbillActivator implements BundleActivator, ServiceListener {
     private final DataSource dataSource;
     private final KillbillEventObservable observable;
     private final OSGIKillbillRegistrar registrar;
+    private final Map<String, ServiceTracker> liveTrackers;
 
 
     private final List<OSGIServiceRegistration> allRegistrationHandlers;
@@ -75,6 +80,7 @@ public class KillbillActivator implements BundleActivator, ServiceListener {
         this.observable = observable;
         this.registrar = new OSGIKillbillRegistrar();
         this.allRegistrationHandlers = ImmutableList.<OSGIServiceRegistration>of(servletRouter, paymentProviderPluginRegistry);
+        this.liveTrackers = new HashMap<String, ServiceTracker>();
 
     }
 
@@ -101,6 +107,9 @@ public class KillbillActivator implements BundleActivator, ServiceListener {
         context.removeServiceListener(this);
         observable.unregister();
         registrar.unregisterAll();
+        for (ServiceTracker tracker : liveTrackers.values()) {
+            tracker.close();
+        }
     }
 
     @Override
@@ -110,16 +119,70 @@ public class KillbillActivator implements BundleActivator, ServiceListener {
             return;
         }
 
+
         final ServiceReference serviceReference = event.getServiceReference();
-        boolean processedServiceChange = false;
+
+        registerUnregisterLiveTrackers(serviceReference, event.getType());
+
         for (OSGIServiceRegistration cur : allRegistrationHandlers) {
             if (listenForServiceType(serviceReference, event.getType(), cur.getServiceType(), cur)) {
-                processedServiceChange = true;
                 break;
             }
         }
-        if (!processedServiceChange) {
-            logger.warn("Did not process ServiceEvent for {} ", serviceReference.getBundle().getSymbolicName());
+    }
+
+    @Override
+    public <S> S getRegisteredOSGIService(final Class<S> serviceType) throws LiveTrackerException {
+        try {
+            ServiceTracker tracker = liveTrackers.get(serviceType.getName());
+            if (tracker == null) {
+                throw new LiveTrackerException("No live tracker for service " + serviceType.getName());
+            }
+            S result = (S) tracker.getService();
+            if (result == null) {
+                throw new LiveTrackerException("Live tracker found a null service for " + serviceType.getName());
+            }
+            return result;
+        } catch (ClassCastException e) {
+            throw new LiveTrackerException("Live tracker got ClassCastException for " + serviceType.getName(), e);
+        }
+    }
+
+
+    private void registerUnregisterLiveTrackers(final ServiceReference serviceReference, final int eventType) {
+        final Object theServiceObject = context.getService(serviceReference);
+        switch (eventType) {
+            case ServiceEvent.REGISTERED:
+                createLiveTrackerForService(theServiceObject);
+                break;
+            case ServiceEvent.UNREGISTERING:
+                removeLiveTrackerForService(theServiceObject);
+                break;
+            default:
+                break;
+        }
+
+    }
+
+    private void createLiveTrackerForService(final Object theServiceObject) {
+        final String serviceClassName = theServiceObject.getClass().getName();
+        synchronized (liveTrackers) {
+            if (liveTrackers.get(serviceClassName) == null) {
+                final ServiceTracker tracker = new ServiceTracker(context, serviceClassName, null);
+                liveTrackers.put(serviceClassName, tracker);
+                tracker.open();
+            }
+        }
+    }
+
+    private void removeLiveTrackerForService(final Object theServiceObject) {
+        final String serviceClassName = theServiceObject.getClass().getName();
+        synchronized (liveTrackers) {
+            ServiceTracker tracker = liveTrackers.get(serviceClassName);
+            if (tracker != null) {
+                tracker.close();
+                liveTrackers.remove(serviceClassName);
+            }
         }
     }
 
@@ -131,14 +194,15 @@ public class KillbillActivator implements BundleActivator, ServiceListener {
             return true;
         }
 
-        final T theService = (T) context.getService(serviceReference);
+        final Object theServiceObject = context.getService(serviceReference);
         // Is that for us? We look for a subclass here for greater flexibility (e.g. HttpServlet for a Servlet service)
-        if (theService == null || !claz.isAssignableFrom(theService.getClass())) {
+        if (theServiceObject == null || !claz.isAssignableFrom(theServiceObject.getClass())) {
             return false;
         }
+        final T theService = (T) theServiceObject;
 
         final String serviceInfo = (String) serviceReference.getProperty(OSGIPluginProperties.PLUGIN_SERVICE_INFO);
-        final OSGIServiceDescriptor desc =  new DefaultOSGIServiceDescriptor(serviceReference.getBundle().getSymbolicName(), serviceName, serviceInfo, claz.getName());
+        final OSGIServiceDescriptor desc = new DefaultOSGIServiceDescriptor(serviceReference.getBundle().getSymbolicName(), serviceName, serviceInfo, claz.getName());
         switch (eventType) {
             case ServiceEvent.REGISTERED:
                 registration.registerService(desc, theService);
diff --git a/osgi/src/main/java/com/ning/billing/osgi/LiveTracker.java b/osgi/src/main/java/com/ning/billing/osgi/LiveTracker.java
new file mode 100644
index 0000000..110c937
--- /dev/null
+++ b/osgi/src/main/java/com/ning/billing/osgi/LiveTracker.java
@@ -0,0 +1,24 @@
+/*
+ * 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 com.ning.billing.osgi.api.LiveTrackerException;
+
+public interface LiveTracker {
+
+    public <S> S getRegisteredOSGIService(final Class<S> serviceType) throws LiveTrackerException;
+}
diff --git a/osgi-bundles/libs/killbill/pom.xml b/osgi-bundles/libs/killbill/pom.xml
index 47ef9c0..eb5c542 100644
--- a/osgi-bundles/libs/killbill/pom.xml
+++ b/osgi-bundles/libs/killbill/pom.xml
@@ -28,24 +28,30 @@
     <packaging>jar</packaging>
     <dependencies>
         <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+            <version>1.3.9</version>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>com.ning.billing</groupId>
             <artifactId>killbill-api</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
diff --git a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/KillbillActivatorBase.java b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/KillbillActivatorBase.java
index bd2056f..3b2da79 100644
--- a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/KillbillActivatorBase.java
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/KillbillActivatorBase.java
@@ -53,24 +53,39 @@ public abstract class KillbillActivatorBase implements BundleActivator {
     public void stop(final BundleContext context) throws Exception {
 
         // Close trackers
-        killbillAPI.close();
-        dispatcher.close();
-        dataSource.close();
-        logService.close();
+        if (killbillAPI != null) {
+            killbillAPI.close();
+            killbillAPI = null;
+        }
+        if (dispatcher != null) {
+            dispatcher.close();
+            dispatcher = null;
+        }
+        if (dataSource != null) {
+            dataSource.close();
+            dataSource = null;
+        }
+        if (logService != null) {
+            logService.close();
+            logService = null;
+        }
 
         try {
             // Remove Killbill event handler
             final OSGIKillbillEventHandler handler = getOSGIKillbillEventHandler();
-            if (handler != null) {
+            if (handler != null && dispatcher != null) {
                 dispatcher.unregisterEventHandler(handler);
+                dispatcher = null;
             }
         } catch (OSGIServiceNotAvailable ignore) {
             // If the system bundle shut down prior to that bundle, we can' unregister our Observer, which is fine.
         }
 
-        // Unregistaer all servies from that bundle
-        registrar.unregisterAll();
-        System.out.println("Good bye world from TestActivator!");
+        // Unregister all servies from that bundle
+        if (registrar != null) {
+            registrar.unregisterAll();
+            registrar = null;
+        }
     }
 
 
diff --git a/osgi-bundles/tests/beatrix/src/test/java/com/ning/billing/osgi/bundles/test/Foo.java b/osgi-bundles/tests/beatrix/src/test/java/com/ning/billing/osgi/bundles/test/Foo.java
new file mode 100644
index 0000000..300374a
--- /dev/null
+++ b/osgi-bundles/tests/beatrix/src/test/java/com/ning/billing/osgi/bundles/test/Foo.java
@@ -0,0 +1,4 @@
+package com.ning.billing.osgi.bundles.test;
+
+public class Foo {
+}
diff --git a/util/src/main/java/com/ning/billing/util/config/OSGIConfig.java b/util/src/main/java/com/ning/billing/util/config/OSGIConfig.java
index bef6e97..59afa86 100644
--- a/util/src/main/java/com/ning/billing/util/config/OSGIConfig.java
+++ b/util/src/main/java/com/ning/billing/util/config/OSGIConfig.java
@@ -48,6 +48,7 @@ public interface OSGIConfig extends KillbillConfig {
              "com.ning.billing.entitlement.api.transfer," +
              "com.ning.billing.entitlement.api.user," +
              "com.ning.billing.invoice.api," +
+             "com.ning.billing," +
              "com.ning.billing.osgi.api," +
              "com.ning.billing.osgi.api.config," +
              "com.ning.billing.overdue," +