killbill-memoizeit

Changes

beatrix/pom.xml 13(+9 -4)

osgi/pom.xml 4(+4 -0)

osgi-bundles/hello/src/main/java/com/ning/billing/osgi/bundles/hello/HelloActivator.java 182(+0 -182)

osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/Logger.java 70(+0 -70)

pom.xml 11(+8 -3)

Details

diff --git a/api/src/main/java/com/ning/billing/osgi/api/OSGIKillbill.java b/api/src/main/java/com/ning/billing/osgi/api/OSGIKillbill.java
index b9a7adc..646afd9 100644
--- a/api/src/main/java/com/ning/billing/osgi/api/OSGIKillbill.java
+++ b/api/src/main/java/com/ning/billing/osgi/api/OSGIKillbill.java
@@ -16,12 +16,9 @@
 
 package com.ning.billing.osgi.api;
 
-import javax.sql.DataSource;
-
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.analytics.api.sanity.AnalyticsSanityApi;
 import com.ning.billing.analytics.api.user.AnalyticsUserApi;
-import com.ning.billing.beatrix.bus.api.ExternalBus;
 import com.ning.billing.catalog.api.CatalogUserApi;
 import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
 import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
@@ -51,32 +48,42 @@ public interface OSGIKillbill {
      * @return the matching API
      */
     public AccountUserApi getAccountUserApi();
+
     public AnalyticsSanityApi getAnalyticsSanityApi();
+
     public AnalyticsUserApi getAnalyticsUserApi();
+
     public CatalogUserApi getCatalogUserApi();
+
     public EntitlementMigrationApi getEntitlementMigrationApi();
+
     public EntitlementTimelineApi getEntitlementTimelineApi();
+
     public EntitlementTransferApi getEntitlementTransferApi();
+
     public EntitlementUserApi getEntitlementUserApi();
+
     public InvoiceMigrationApi getInvoiceMigrationApi();
+
     public InvoicePaymentApi getInvoicePaymentApi();
+
     public InvoiceUserApi getInvoiceUserApi();
+
     public OverdueUserApi getOverdueUserApi();
+
     public PaymentApi getPaymentApi();
+
     public TenantUserApi getTenantUserApi();
+
     public UsageUserApi getUsageUserApi();
+
     public AuditUserApi getAuditUserApi();
+
     public CustomFieldUserApi getCustomFieldUserApi();
-    public ExportUserApi getExportUserApi();
-    public TagUserApi getTagUserApi();
 
-    /**
-     * Used by the OSGI bundles to register interest into Killbill events
-     *
-     * @return the externalBus
-     */
-    public ExternalBus getExternalBus();
+    public ExportUserApi getExportUserApi();
 
+    public TagUserApi getTagUserApi();
 
     /**
      * Used by the OSGI bundles to discover their configuration
@@ -84,11 +91,4 @@ public interface OSGIKillbill {
      * @return the PluginConfigServiceApi
      */
     public PluginConfigServiceApi getPluginConfigServiceApi();
-
-
-    /**
-     * Used by the OSGI bundles to be able to access their own sql tables
-     * @return the dataSource for the OSGI bundles
-     */
-    public DataSource getDataSource();
 }
diff --git a/api/src/main/java/com/ning/billing/osgi/api/OSGIPluginProperties.java b/api/src/main/java/com/ning/billing/osgi/api/OSGIPluginProperties.java
index 2c4bb7c..e1873e0 100644
--- a/api/src/main/java/com/ning/billing/osgi/api/OSGIPluginProperties.java
+++ b/api/src/main/java/com/ning/billing/osgi/api/OSGIPluginProperties.java
@@ -16,8 +16,22 @@
 
 package com.ning.billing.osgi.api;
 
+/**
+ * Those represents the properties that plugin can use when registering services
+ * and that Killbill knows how to interpret. At a minimum, the plugin should use PLUGIN_NAME_PROP
+ */
 public interface OSGIPluginProperties {
 
+    /** Name of the plugin when it registers itself */
+    // TODO We should make sure that this mataches the 'symbolic name' of the plugin, or if not how those two play together
     public static final String PLUGIN_NAME_PROP = "killbill.pluginName";
 
+    /** Name of the instnace of the plugin; if 2 instances of the same plugin register */
+    public static final String PLUGIN_INSTANCE_PROP = "killbill.pluginInstance";
+
+    /** Used to export an additional configuration string for that service
+     *  For instance for Servlet services this is used to specify the path of the servlet.
+     */
+    public static final String PLUGIN_SERVICE_INFO = "killbill.pluginServiceInfo";
+
 }
diff --git a/api/src/main/java/com/ning/billing/osgi/api/OSGIServiceDescriptor.java b/api/src/main/java/com/ning/billing/osgi/api/OSGIServiceDescriptor.java
new file mode 100644
index 0000000..d281471
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/osgi/api/OSGIServiceDescriptor.java
@@ -0,0 +1,43 @@
+/*
+ * 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 OSGIServiceDescriptor {
+
+    /**
+     * @return the symbolic name of the OSGI plugin registering that service
+     */
+    public String getPluginSymbolicName();
+
+    /**
+     *
+     * @return the unique of that service-- plugin should rely on namespace to enforce the uniqueness
+     */
+    public String getServiceName();
+
+    /**
+     *
+     * @return additional service info that can be interpreted by the OSGIServiceRegistration system
+     */
+    public String getServiceInfo();
+
+    /**
+     *
+     * @return the type of the service being registered
+     */
+    public String getServiceType();
+}
diff --git a/api/src/main/java/com/ning/billing/osgi/api/OSGIServiceRegistration.java b/api/src/main/java/com/ning/billing/osgi/api/OSGIServiceRegistration.java
index 83293e0..cfa3127 100644
--- a/api/src/main/java/com/ning/billing/osgi/api/OSGIServiceRegistration.java
+++ b/api/src/main/java/com/ning/billing/osgi/api/OSGIServiceRegistration.java
@@ -16,11 +16,9 @@
 
 package com.ning.billing.osgi.api;
 
-import java.util.List;
 import java.util.Set;
 
 /**
- *
  * The purpose is to register within Killbill OSGI services
  * that were exported by specific Killbill plugins
  *
@@ -28,34 +26,25 @@ import java.util.Set;
  */
 public interface OSGIServiceRegistration<T> {
 
-    /**
-     *
-     * @param pluginName the name of plugin
-     * @param service    the instance that should be registered
-     */
-    void registerService(String pluginName, T service);
+    void registerService(OSGIServiceDescriptor desc, T service);
 
     /**
-     *
-     * @param pluginName the name of plugin
+     * @param serviceName the name of the service as it was registered
      */
-    void unregisterService(String pluginName);
+    void unregisterService(String serviceName);
 
     /**
-     *
-     * @param pluginName the name of plugin
+     * @param serviceName the name of the service as it was registered
      * @return the instance that was registered under that name
      */
-    T getServiceForPluginName(String pluginName);
+    T getServiceForName(String serviceName);
 
     /**
-     *
-     * @return the set of all the plugins registered
+     * @return the set of all the service registered
      */
-    Set<String> getAllServiceForPluginName();
+    Set<String> getAllServices();
 
     /**
-     *
      * @return the type of service that is registered under that OSGIServiceRegistration
      */
     Class<T> getServiceType();

beatrix/pom.xml 13(+9 -4)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index b1bf7e5..7472253 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -57,15 +57,19 @@
         </dependency>
         <dependency>
             <groupId>com.ning.billing</groupId>
-            <artifactId>killbill-osgi-bundles-test</artifactId>
+            <artifactId>killbill-tenant</artifactId>
         </dependency>
         <dependency>
             <groupId>com.ning.billing</groupId>
-            <artifactId>killbill-tenant</artifactId>
+            <artifactId>killbill-usage</artifactId>
         </dependency>
         <dependency>
             <groupId>com.ning.billing</groupId>
-            <artifactId>killbill-usage</artifactId>
+            <artifactId>killbill-osgi-bundles-test-beatrix</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-osgi-bundles-test-payment</artifactId>
         </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
@@ -189,7 +193,8 @@
                         <phase>initialize</phase>
                         <configuration>
                             <tasks>
-                                <copy file="${basedir}/../osgi-bundles/test/target/killbill-osgi-bundles-test-${project.version}-jar-with-dependencies.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-test-${project.version}-jar-with-dependencies.jar"/>
+                                <copy file="${basedir}/../osgi-bundles/tests/beatrix/target/killbill-osgi-bundles-test-beatrix-${project.version}-jar-with-dependencies.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-test-beatrix-${project.version}-jar-with-dependencies.jar"/>
+                                <copy file="${basedir}/../osgi-bundles/tests/payment/target/killbill-osgi-bundles-test-payment-${project.version}-jar-with-dependencies.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-test-payment-${project.version}-jar-with-dependencies.jar"/>
                             </tasks>
                         </configuration>
                         <goals>
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
index 47df951..ae1fc99 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
@@ -79,7 +79,10 @@ import static org.testng.Assert.assertNotNull;
 
 public class BeatrixIntegrationModule extends AbstractModule {
 
-    public static final String PLUGIN_NAME = "yoyo";
+    public static final String NON_OSGI_PLUGIN_NAME = "yoyo";
+
+    // Same name the osgi-payment-test plugin uses to register its service
+    public static final String OSGI_PLUGIN_NAME = "osgiPaymentPlugin";
 
     private final ConfigSource configSource;
 
@@ -144,7 +147,7 @@ public class BeatrixIntegrationModule extends AbstractModule {
 
         @Override
         protected void installPaymentProviderPlugins(final PaymentConfig config) {
-            install(new MockPaymentProviderPluginModule(PLUGIN_NAME, TestIntegrationBase.getClock()));
+            install(new MockPaymentProviderPluginModule(NON_OSGI_PLUGIN_NAME, TestIntegrationBase.getClock()));
         }
     }
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestBasicOSGIWithTestBundle.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestBasicOSGIWithTestBundle.java
index 3c3f975..1630a41 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestBasicOSGIWithTestBundle.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestBasicOSGIWithTestBundle.java
@@ -59,7 +59,7 @@ import static com.jayway.awaitility.Awaitility.await;
  */
 public class TestBasicOSGIWithTestBundle extends TestOSGIBase {
 
-    private final String BUNDLE_TEST_RESOURCE = "killbill-osgi-bundles-test";
+    private final String BUNDLE_TEST_RESOURCE = "killbill-osgi-bundles-test-beatrix";
 
     @Inject
     private OSGIServiceRegistration<PaymentPluginApi> paymentPluginApiOSGIServiceRegistration;
@@ -93,7 +93,7 @@ public class TestBasicOSGIWithTestBundle extends TestOSGIBase {
         assertTor.assertPluginInitialized();
 
         // Create an account and expect test bundle listen to KB events and write the external name in its table
-        final Account account = createAccountWithPaymentMethod(getAccountData(1));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
         assertTor.assertPluginReceievdAccountCreationEvent(account.getExternalKey());
 
         // Retrieve the PaymentPluginApi that the test bundle registered
@@ -107,7 +107,7 @@ public class TestBasicOSGIWithTestBundle extends TestOSGIBase {
     }
 
     private PaymentPluginApi getTestPluginPaymentApi() {
-        PaymentPluginApi result = paymentPluginApiOSGIServiceRegistration.getServiceForPluginName("test");
+        PaymentPluginApi result = paymentPluginApiOSGIServiceRegistration.getServiceForName("test");
         Assert.assertNotNull(result);
         return result;
     }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestOSGIIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestOSGIIntegration.java
index 2be1879..36fd2e5 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestOSGIIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestOSGIIntegration.java
@@ -16,15 +16,12 @@
 
 package com.ning.billing.beatrix.integration.osgi;
 
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
-import com.ning.billing.beatrix.integration.BeatrixIntegrationModule;
-
 public class TestOSGIIntegration extends TestOSGIBase {
 
     @Test(groups = "slow")
     public void testJRubyIntegration() throws Exception {
-        createAccountWithPaymentMethod(getAccountData(1));
+        createAccountWithNonOsgiPaymentMethod(getAccountData(1));
     }
 }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestPaymentOSGIWithTestPaymentBundle.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestPaymentOSGIWithTestPaymentBundle.java
new file mode 100644
index 0000000..bbe1df6
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestPaymentOSGIWithTestPaymentBundle.java
@@ -0,0 +1,186 @@
+/*
+ * 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.beatrix.integration.osgi;
+
+import java.math.BigDecimal;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.joda.time.LocalDate;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.beatrix.integration.BeatrixIntegrationModule;
+import com.ning.billing.beatrix.osgi.SetupBundleWithAssertion;
+import com.ning.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
+import com.ning.billing.beatrix.util.PaymentChecker.ExpectedPaymentCheck;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItemType;
+import com.ning.billing.osgi.api.OSGIServiceRegistration;
+import com.ning.billing.payment.api.PaymentStatus;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiWithTestControl;
+
+public class TestPaymentOSGIWithTestPaymentBundle extends TestOSGIBase {
+
+    private final String BUNDLE_TEST_RESOURCE = "killbill-osgi-bundles-test-payment";
+
+    @Inject
+    private OSGIServiceRegistration<PaymentPluginApi> paymentPluginApiOSGIServiceRegistration;
+
+    @BeforeClass(groups = "slow")
+    public void beforeClass() throws Exception {
+
+        super.beforeClass();
+
+        // This is extracted from surefire system configuration-- needs to be added explicitly in IntelliJ for correct running
+        final String killbillVersion = System.getProperty("killbill.version");
+        SetupBundleWithAssertion setupTest = new SetupBundleWithAssertion(BUNDLE_TEST_RESOURCE, osgiConfig, killbillVersion);
+        setupTest.setupBundle();
+
+    }
+
+    @BeforeMethod(groups = "slow")
+    public void beforeMethod() throws Exception {
+        super.beforeMethod();
+        getTestPluginPaymentApi().resetToNormalbehavior();
+    }
+
+    @Test(groups = "slow")
+    public void testBasicProcessPaymentOK() throws Exception {
+        final PaymentPluginApiWithTestControl paymentPluginApi = getTestPluginPaymentApi();
+        paymentPluginApi.processPayment(UUID.randomUUID(), UUID.randomUUID(), BigDecimal.TEN, callContext);
+    }
+
+    @Test(groups = "slow")
+    public void testBasicProcessPaymentWithPaymentPluginApiException() throws Exception {
+
+        boolean gotException = false;
+        try {
+            final PaymentPluginApiWithTestControl paymentPluginApi = getTestPluginPaymentApi();
+            final PaymentPluginApiException e = new PaymentPluginApiException("test-error", "foo");
+
+            paymentPluginApi.setPaymentPluginApiExceptionOnNextCalls(e);
+            paymentPluginApi.processPayment(UUID.randomUUID(), UUID.randomUUID(), BigDecimal.TEN, callContext);
+            Assert.fail("Expected to fail with " + e.toString());
+        } catch (PaymentPluginApiException e) {
+            gotException = true;
+        }
+        Assert.assertTrue(gotException);
+    }
+
+    @Test(groups = "slow")
+    public void testBasicProcessPaymentWithRuntimeException() throws Exception {
+
+        boolean gotException = false;
+        try {
+            final PaymentPluginApiWithTestControl paymentPluginApi = getTestPluginPaymentApi();
+            final RuntimeException e = new RuntimeException("test-error");
+
+            paymentPluginApi.setPaymentRuntimeExceptionOnNextCalls(e);
+            paymentPluginApi.processPayment(UUID.randomUUID(), UUID.randomUUID(), BigDecimal.TEN, callContext);
+            Assert.fail("Expected to fail with " + e.toString());
+        } catch (RuntimeException e) {
+            gotException = true;
+        }
+        Assert.assertTrue(gotException);
+    }
+
+
+    @Test(groups = "slow")
+    public void testIntegrationOK() throws Exception {
+        setupIntegration(null, null);
+    }
+
+    @Test(groups = "slow")
+    public void testIntegrationWithPaymentPluginApiException() throws Exception {
+        final PaymentPluginApiException e = new PaymentPluginApiException("test-error", "foo");
+        setupIntegration(e, null);
+    }
+
+    @Test(groups = "slow")
+    public void testIntegrationWithRuntimeException() throws Exception {
+        final RuntimeException e = new RuntimeException("test-error");
+        setupIntegration(null, e);
+    }
+
+
+    private void setupIntegration(final PaymentPluginApiException expectedException, final RuntimeException expectedRuntimeException) throws Exception {
+
+        final PaymentPluginApiWithTestControl paymentPluginApi = getTestPluginPaymentApi();
+
+        final AccountData accountData = getAccountData(1);
+        final Account account = createAccountWithOsgiPaymentMethod(accountData);
+
+        // We take april as it has 30 days (easier to play with BCD)
+        // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
+        clock.setDay(new LocalDate(2012, 4, 1));
+
+        final SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", callContext);
+        //
+        // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE NextEvent.INVOICE
+        //
+        final Subscription bpSubscription = createSubscriptionAndCheckForCompletion(bundle.getId(), "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.INVOICE);
+        //
+        // ADD ADD_ON ON THE SAME DAY TO TRIGGER PAYMENT
+        //
+
+        final List<NextEvent> expectedEvents = new LinkedList<NextEvent>();
+        expectedEvents.add(NextEvent.CREATE);
+        expectedEvents.add(NextEvent.INVOICE);
+        if (expectedException == null && expectedRuntimeException == null) {
+            expectedEvents.add(NextEvent.PAYMENT);
+        } else if (expectedException != null) {
+            paymentPluginApi.setPaymentPluginApiExceptionOnNextCalls(expectedException);
+        } else if (expectedRuntimeException != null) {
+            paymentPluginApi.setPaymentRuntimeExceptionOnNextCalls(expectedRuntimeException);
+
+        }
+
+        createSubscriptionAndCheckForCompletion(bundle.getId(), "Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, expectedEvents.toArray(new NextEvent[expectedEvents.size()]));
+        Invoice invoice = invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("399.95")));
+
+        if (expectedException == null && expectedRuntimeException == null) {
+            paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 4, 1), new BigDecimal("399.95"), PaymentStatus.SUCCESS, invoice.getId(), Currency.USD));
+        } else if (expectedException != null) {
+            paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 4, 1), new BigDecimal("399.95"), PaymentStatus.PLUGIN_FAILURE, invoice.getId(), Currency.USD));
+        } else if (expectedRuntimeException != null) {
+            paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 4, 1), new BigDecimal("399.95"), PaymentStatus.UNKNOWN, invoice.getId(), Currency.USD));
+        }
+    }
+
+
+    private PaymentPluginApiWithTestControl getTestPluginPaymentApi() {
+        PaymentPluginApiWithTestControl result = (PaymentPluginApiWithTestControl) paymentPluginApiOSGIServiceRegistration.getServiceForName(BeatrixIntegrationModule.OSGI_PLUGIN_NAME);
+        Assert.assertNotNull(result);
+        return result;
+    }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestBillingAlignment.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestBillingAlignment.java
index c4984c9..1fecc27 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestBillingAlignment.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestBillingAlignment.java
@@ -19,12 +19,10 @@ package com.ning.billing.beatrix.integration.overdue;
 import java.math.BigDecimal;
 
 import org.joda.time.LocalDate;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.api.TestApiListener.NextEvent;
-import com.ning.billing.beatrix.integration.BeatrixIntegrationModule;
 import com.ning.billing.beatrix.integration.TestIntegrationBase;
 import com.ning.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -45,7 +43,7 @@ public class TestBillingAlignment extends TestIntegrationBase {
     @Test(groups = "slow", enabled = false)
     public void testTransitonAccountBAToSubscriptionBA() throws Exception {
 
-        final Account account = createAccountWithPaymentMethod(getAccountData(1));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
 
         // We take april as it has 30 days (easier to play with BCD)
         // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueBase.java
index a15bcd0..3594ec2 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueBase.java
@@ -79,10 +79,10 @@ public abstract class TestOverdueBase extends TestIntegrationBase {
         final OverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, OverdueConfig.class);
         overdueWrapperFactory.setOverdueConfig(config);
 
-        account = createAccountWithPaymentMethod(getAccountData(0));
+        account = createAccountWithNonOsgiPaymentMethod(getAccountData(0));
         assertNotNull(account);
 
-        paymentApi.addPaymentMethod(BeatrixIntegrationModule.PLUGIN_NAME, account, true, paymentMethodPlugin, callContext);
+        paymentApi.addPaymentMethod(BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, account, true, paymentMethodPlugin, callContext);
 
         bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", callContext);
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index b66e107..5ad8c97 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -21,7 +21,6 @@ import java.util.Collection;
 
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.api.TestApiListener.NextEvent;
@@ -255,7 +254,7 @@ public class TestOverdueIntegration extends TestOverdueBase {
         checkChangePlanWithOverdueState(baseSubscription, true);
 
         // Add a payment method and set it as default
-        paymentApi.addPaymentMethod(BeatrixIntegrationModule.PLUGIN_NAME, account, true, paymentMethodPlugin, callContext);
+        paymentApi.addPaymentMethod(BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, account, true, paymentMethodPlugin, callContext);
 
         // Pay all invoices
         final Collection<Invoice> invoices = invoiceUserApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday(), callContext);
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
index f6863b4..a139e9e 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
@@ -27,7 +27,6 @@ import org.joda.time.LocalDate;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.ObjectType;
@@ -251,7 +250,7 @@ public class TestAnalytics extends TestIntegrationBase {
         Assert.assertNull(invoicePaymentsForAccount.get(0).getExtFirstPaymentRefId());
         Assert.assertNull(invoicePaymentsForAccount.get(0).getExtSecondPaymentRefId());
         Assert.assertEquals(invoicePaymentsForAccount.get(0).getProcessingStatus(), PaymentStatus.PAYMENT_FAILURE.toString());
-        Assert.assertEquals(invoicePaymentsForAccount.get(0).getPluginName(), BeatrixIntegrationModule.PLUGIN_NAME);
+        Assert.assertEquals(invoicePaymentsForAccount.get(0).getPluginName(), BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME);
 
         // Verify the account object has been updated
         Assert.assertEquals(analyticsUserApi.getAccountByKey(account.getExternalKey(), callContext).getBalance(),
@@ -340,7 +339,7 @@ public class TestAnalytics extends TestIntegrationBase {
         Assert.assertNull(analyticsUserApi.getAccountByKey(accountData.getExternalKey(), callContext));
 
         // Create an account
-        final Account account = createAccountWithPaymentMethod(accountData);
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
         Assert.assertNotNull(account);
 
         waitALittle();
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBundleTransfer.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBundleTransfer.java
index c27ac26..2c6b654 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBundleTransfer.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBundleTransfer.java
@@ -47,7 +47,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
     @Test(groups = "slow")
     public void testBundleTransferWithBPAnnualOnly() throws Exception {
 
-        final Account account = createAccountWithPaymentMethod(getAccountData(3));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(3));
 
         // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
 
@@ -84,7 +84,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
         assertListenerStatus();
 
         // BUNDLE TRANSFER
-        final Account newAccount = createAccountWithPaymentMethod(getAccountData(17));
+        final Account newAccount = createAccountWithNonOsgiPaymentMethod(getAccountData(17));
 
         busHandler.pushExpectedEvent(NextEvent.TRANSFER);
         busHandler.pushExpectedEvent(NextEvent.INVOICE);
@@ -107,7 +107,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
     @Test(groups = "slow")
     public void testBundleTransferWithBPMonthlyOnly() throws Exception {
 
-        final Account account = createAccountWithPaymentMethod(getAccountData(0));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(0));
 
         // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
 
@@ -144,7 +144,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
         assertListenerStatus();
 
         // BUNDLE TRANSFER
-        final Account newAccount = createAccountWithPaymentMethod(getAccountData(0));
+        final Account newAccount = createAccountWithNonOsgiPaymentMethod(getAccountData(0));
 
         busHandler.pushExpectedEvent(NextEvent.TRANSFER);
         busHandler.pushExpectedEvent(NextEvent.INVOICE);
@@ -174,7 +174,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
     @Test(groups = "slow")
     public void testBundleTransferWithBPMonthlyOnlyWIthCancellationImm() throws Exception {
 
-        final Account account = createAccountWithPaymentMethod(getAccountData(9));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(9));
 
         // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
 
@@ -211,7 +211,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
         assertListenerStatus();
 
         // BUNDLE TRANSFER
-        final Account newAccount = createAccountWithPaymentMethod(getAccountData(15));
+        final Account newAccount = createAccountWithNonOsgiPaymentMethod(getAccountData(15));
 
         busHandler.pushExpectedEvent(NextEvent.CANCEL);
         busHandler.pushExpectedEvent(NextEvent.TRANSFER);
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestEntitlement.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestEntitlement.java
index af1f885..adea394 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestEntitlement.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestEntitlement.java
@@ -49,7 +49,7 @@ public class TestEntitlement extends TestIntegrationBase {
     public void testForcePolicy() throws Exception {
         // We take april as it has 30 days (easier to play with BCD)
         final LocalDate today = new LocalDate(2012, 4, 1);
-        final Account account = createAccountWithPaymentMethod(getAccountData(1));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
 
         // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
         clock.setDeltaFromReality(today.toDateTimeAtCurrentTime(DateTimeZone.UTC).getMillis() - clock.getUTCNow().getMillis());
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index 7b50732..8453fd7 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -23,7 +23,6 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 import org.joda.time.Interval;
 import org.joda.time.LocalDate;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
@@ -54,7 +53,7 @@ public class TestIntegration extends TestIntegrationBase {
     public void testCancelBPWithAOTheSameDay() throws Exception {
 
         final AccountData accountData = getAccountData(1);
-        final Account account = createAccountWithPaymentMethod(accountData);
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
         accountChecker.checkAccount(account.getId(), accountData, callContext);
 
         // We take april as it has 30 days (easier to play with BCD)
@@ -101,7 +100,7 @@ public class TestIntegration extends TestIntegrationBase {
         final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
 
         log.info("Beginning test with BCD of " + billingDay);
-        final Account account = createAccountWithPaymentMethod(getAccountData(billingDay));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
 
         // set clock to the initial start date
         clock.setTime(initialCreationDate);
@@ -183,7 +182,7 @@ public class TestIntegration extends TestIntegrationBase {
         final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
 
         log.info("Beginning test with BCD of " + billingDay);
-        final Account account = createAccountWithPaymentMethod(getAccountData(billingDay));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
 
         // set clock to the initial start date
         clock.setTime(initialCreationDate);
@@ -265,7 +264,7 @@ public class TestIntegration extends TestIntegrationBase {
         final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
 
         log.info("Beginning test with BCD of " + billingDay);
-        final Account account = createAccountWithPaymentMethod(getAccountData(billingDay));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
 
         // set clock to the initial start date
         clock.setTime(initialCreationDate);
@@ -398,7 +397,7 @@ public class TestIntegration extends TestIntegrationBase {
         final DateTime initialDate = new DateTime(2012, 4, 25, 0, 13, 42, 0, testTimeZone);
         clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
 
-        final Account account = createAccountWithPaymentMethod(getAccountData(25));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(25));
         assertNotNull(account);
 
         final SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", callContext);
@@ -477,7 +476,7 @@ public class TestIntegration extends TestIntegrationBase {
 
         log.info("Starting testRepairForInvoicing");
 
-        final Account account = createAccountWithPaymentMethod(getAccountData(1));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
         final UUID accountId = account.getId();
         assertNotNull(account);
 
@@ -510,7 +509,7 @@ public class TestIntegration extends TestIntegrationBase {
         final int billingDay = 2;
 
         log.info("Beginning test with BCD of " + billingDay);
-        final Account account = createAccountWithPaymentMethod(getAccountData(billingDay));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
         final UUID accountId = account.getId();
         assertNotNull(account);
 
@@ -582,7 +581,7 @@ public class TestIntegration extends TestIntegrationBase {
         final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
         clock.setDeltaFromReality(initialCreationDate.getMillis() - clock.getUTCNow().getMillis());
 
-        final Account account = createAccountWithPaymentMethod(getAccountData(2));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(2));
         final UUID accountId = account.getId();
 
         final String productName = "Blowdart";
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index 682201f..d1c30e4 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -154,7 +154,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
     @Inject
     protected PaymentApi paymentApi;
 
-    @Named(BeatrixIntegrationModule.PLUGIN_NAME)
+    @Named(BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME)
     @Inject
     protected MockPaymentProviderPlugin paymentPlugin;
 
@@ -306,7 +306,15 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
         return (SubscriptionData) ((BlockingSubscription) sub).getDelegateSubscription();
     }
 
-    protected Account createAccountWithPaymentMethod(final AccountData accountData) throws Exception {
+    protected Account createAccountWithOsgiPaymentMethod(final AccountData accountData) throws Exception {
+        return createAccountWithPaymentMethod(accountData, BeatrixIntegrationModule.OSGI_PLUGIN_NAME);
+    }
+
+    protected Account createAccountWithNonOsgiPaymentMethod(final AccountData accountData) throws Exception {
+        return createAccountWithPaymentMethod(accountData, BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME);
+    }
+
+    private Account createAccountWithPaymentMethod(final AccountData accountData, final String paymentPluginName) throws Exception {
         final Account account = accountUserApi.createAccount(accountData, callContext);
         assertNotNull(account);
 
@@ -332,7 +340,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
             }
         };
 
-        paymentApi.addPaymentMethod(BeatrixIntegrationModule.PLUGIN_NAME, account, true, info, callContext);
+        paymentApi.addPaymentMethod(paymentPluginName, account, true, info, callContext);
         return accountUserApi.getAccountById(account.getId(), callContext);
     }
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
index fa14d21..3fe7604 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
@@ -22,7 +22,6 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.ObjectType;
@@ -66,7 +65,7 @@ public class TestIntegrationWithAutoInvoiceOffTag extends TestIntegrationBase {
     @BeforeMethod(groups = {"slow"})
     public void beforeMethod() throws Exception {
         super.beforeMethod();
-        account = createAccountWithPaymentMethod(getAccountData(25));
+        account = createAccountWithNonOsgiPaymentMethod(getAccountData(25));
         assertNotNull(account);
 
         bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", callContext);
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoPayOff.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoPayOff.java
index bd07214..ae23993 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoPayOff.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoPayOff.java
@@ -22,7 +22,6 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.ObjectType;
@@ -73,7 +72,7 @@ public class TestIntegrationWithAutoPayOff extends TestIntegrationBase {
     @BeforeMethod(groups = {"slow"})
     public void beforeMethod() throws Exception {
         super.beforeMethod();
-        account = createAccountWithPaymentMethod(getAccountData(25));
+        account = createAccountWithNonOsgiPaymentMethod(getAccountData(25));
         assertNotNull(account);
 
         bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", callContext);
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestPaymentRefund.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestPaymentRefund.java
index 4afd2b8..f3e829b 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestPaymentRefund.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestPaymentRefund.java
@@ -26,7 +26,6 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
@@ -100,7 +99,7 @@ public class TestPaymentRefund extends TestIntegrationBase {
         final int billingDay = 31;
         initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
 
-        account = createAccountWithPaymentMethod(getAccountData(billingDay));
+        account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
 
         // set clock to the initial start date
         clock.setTime(initialCreationDate);
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestPublicBus.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestPublicBus.java
index db26e0c..a7349b9 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestPublicBus.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestPublicBus.java
@@ -22,7 +22,6 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
@@ -78,7 +77,7 @@ public class TestPublicBus extends TestIntegrationBase {
         final int billingDay = 2;
 
         log.info("Beginning test with BCD of " + billingDay);
-        final Account account = createAccountWithPaymentMethod(getAccountData(billingDay));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
         final UUID accountId = account.getId();
         assertNotNull(account);
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
index 170f015..59d4cae 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
@@ -24,7 +24,6 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 import org.joda.time.Interval;
 import org.testng.Assert;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
@@ -69,7 +68,7 @@ public class TestRepairIntegration extends TestIntegrationBase {
         final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
         clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
 
-        final Account account = createAccountWithPaymentMethod(getAccountData(25));
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(25));
 
         final SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", callContext);
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/osgi/SetupBundleWithAssertion.java b/beatrix/src/test/java/com/ning/billing/beatrix/osgi/SetupBundleWithAssertion.java
index fc23796..1b65c63 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/osgi/SetupBundleWithAssertion.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/osgi/SetupBundleWithAssertion.java
@@ -119,6 +119,7 @@ public class SetupBundleWithAssertion {
 
     private PluginJavaConfig extractBundleTestResource() {
 
+
         final String resourceName = bundleName + "-" + killbillVersion + "-jar-with-dependencies.jar";
         final URL resourceUrl = Resources.getResource(resourceName);
         if (resourceUrl != null) {
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/util/PaymentChecker.java b/beatrix/src/test/java/com/ning/billing/beatrix/util/PaymentChecker.java
index 233679e..2763aed 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/util/PaymentChecker.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/util/PaymentChecker.java
@@ -53,7 +53,11 @@ public class PaymentChecker {
         final List<Payment> payments = paymentApi.getAccountPayments(accountId, context);
         Assert.assertEquals(payments.size(), paymentOrderingNumber);
         final Payment payment = payments.get(paymentOrderingNumber - 1);
-        checkPayment(accountId, payment, context, expected);
+        if (payment.getPaymentStatus() == PaymentStatus.UNKNOWN) {
+            checkPaymentNoAuditForRuntimeException(accountId, payment, context, expected);
+        } else {
+            checkPayment(accountId, payment, context, expected);
+        }
         return payment;
     }
 
@@ -66,6 +70,14 @@ public class PaymentChecker {
         auditChecker.checkPaymentCreated(payment, context);
     }
 
+    private void checkPaymentNoAuditForRuntimeException(final UUID accountId, final Payment payment, final CallContext context, final ExpectedPaymentCheck expected) {
+        Assert.assertEquals(payment.getAccountId(), accountId);
+        Assert.assertTrue(payment.getAmount().compareTo(expected.getAmount()) == 0);
+        Assert.assertEquals(payment.getPaymentStatus(),expected.getStatus());
+        Assert.assertEquals(payment.getInvoiceId(), expected.getInvoiceId());
+        Assert.assertEquals(payment.getCurrency(), expected.getCurrency());
+    }
+
     public static class ExpectedPaymentCheck {
 
         private final LocalDate paymentDate;

osgi/pom.xml 4(+4 -0)

diff --git a/osgi/pom.xml b/osgi/pom.xml
index bf2cc58..fb15528 100644
--- a/osgi/pom.xml
+++ b/osgi/pom.xml
@@ -53,6 +53,10 @@
             <artifactId>killbill-util</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-osgi-bundles-lib-killbill</artifactId>
+        </dependency>
+        <dependency>
             <groupId>com.google.inject</groupId>
             <artifactId>guice</artifactId>
             <scope>provided</scope>
diff --git a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIKillbill.java b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIKillbill.java
index 519465f..ea43446 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIKillbill.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIKillbill.java
@@ -23,7 +23,6 @@ import javax.sql.DataSource;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.analytics.api.sanity.AnalyticsSanityApi;
 import com.ning.billing.analytics.api.user.AnalyticsUserApi;
-import com.ning.billing.beatrix.bus.api.ExternalBus;
 import com.ning.billing.catalog.api.CatalogUserApi;
 import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
 import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
@@ -65,15 +64,10 @@ public class DefaultOSGIKillbill implements OSGIKillbill {
     private final CustomFieldUserApi customFieldUserApi;
     private final ExportUserApi exportUserApi;
     private final TagUserApi tagUserApi;
-
-    private final ExternalBus externalBus;
     private final PluginConfigServiceApi configServiceApi;
 
-    private final DataSource dataSource;
-
     @Inject
-    public DefaultOSGIKillbill(@Named(DefaultOSGIModule.OSGI_NAMED) final DataSource dataSource,
-                               final AccountUserApi accountUserApi,
+    public DefaultOSGIKillbill(final AccountUserApi accountUserApi,
                                final AnalyticsSanityApi analyticsSanityApi,
                                final AnalyticsUserApi analyticsUserApi,
                                final CatalogUserApi catalogUserApi,
@@ -92,9 +86,7 @@ public class DefaultOSGIKillbill implements OSGIKillbill {
                                final CustomFieldUserApi customFieldUserApi,
                                final ExportUserApi exportUserApi,
                                final TagUserApi tagUserApi,
-                               final ExternalBus externalBus,
                                final PluginConfigServiceApi configServiceApi) {
-        this.dataSource = dataSource;
         this.accountUserApi = accountUserApi;
         this.analyticsSanityApi = analyticsSanityApi;
         this.analyticsUserApi = analyticsUserApi;
@@ -114,7 +106,6 @@ public class DefaultOSGIKillbill implements OSGIKillbill {
         this.customFieldUserApi = customFieldUserApi;
         this.exportUserApi = exportUserApi;
         this.tagUserApi = tagUserApi;
-        this.externalBus = externalBus;
         this.configServiceApi = configServiceApi;
     }
 
@@ -214,17 +205,7 @@ public class DefaultOSGIKillbill implements OSGIKillbill {
     }
 
     @Override
-    public ExternalBus getExternalBus() {
-        return externalBus;
-    }
-
-    @Override
     public PluginConfigServiceApi getPluginConfigServiceApi() {
         return configServiceApi;
     }
-
-    @Override
-    public DataSource getDataSource() {
-        return dataSource;
-    }
 }
diff --git a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIServiceDescriptor.java b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIServiceDescriptor.java
new file mode 100644
index 0000000..dcbcd4d
--- /dev/null
+++ b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIServiceDescriptor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.OSGIServiceDescriptor;
+
+public class DefaultOSGIServiceDescriptor implements OSGIServiceDescriptor {
+
+    private final String pluginSymbolicName;
+    private final String serviceName;
+    private final String serviceInfo;
+    private final String serviceType;
+
+    public DefaultOSGIServiceDescriptor(final String pluginSymbolicName, final String serviceName, final String serviceInfo, final String serviceType) {
+        this.pluginSymbolicName = pluginSymbolicName;
+        this.serviceName = serviceName;
+        this.serviceInfo = serviceInfo;
+        this.serviceType = serviceType;
+    }
+
+    @Override
+    public String getPluginSymbolicName() {
+        return pluginSymbolicName;
+    }
+
+    @Override
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    @Override
+    public String getServiceInfo() {
+        return serviceInfo;
+    }
+
+    @Override
+    public String getServiceType() {
+        return serviceType;
+    }
+}
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 42af5aa..0e9ef94 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,6 +27,7 @@ import org.skife.config.ConfigurationObjectFactory;
 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.PureOSGIBundleFinder;
 import com.ning.billing.osgi.api.OSGIKillbill;
 import com.ning.billing.osgi.api.OSGIService;
@@ -84,6 +85,7 @@ public class DefaultOSGIModule extends AbstractModule {
         bind(PluginConfigServiceApi.class).to(DefaultPluginConfigServiceApi.class).asEagerSingleton();
         bind(OSGIKillbill.class).to(DefaultOSGIKillbill.class).asEagerSingleton();
         bind(OSGIDataSourceProvider.class).asEagerSingleton();
+        bind(KillbillEventObservable.class).asEagerSingleton();
         bind(DataSource.class).annotatedWith(Names.named(OSGI_NAMED)).toProvider(OSGIDataSourceProvider.class).asEagerSingleton();
     }
 }
diff --git a/osgi/src/main/java/com/ning/billing/osgi/http/DefaultHttpService.java b/osgi/src/main/java/com/ning/billing/osgi/http/DefaultHttpService.java
index a5d606c..30220f7 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/http/DefaultHttpService.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/http/DefaultHttpService.java
@@ -46,7 +46,7 @@ public class DefaultHttpService implements HttpService {
             throw new IllegalArgumentException("Invalid servlet (null)");
         }
 
-        servletRouter.registerService(alias, servlet);
+        servletRouter.registerServiceFromPath(alias, servlet);
     }
 
     @Override
@@ -61,7 +61,7 @@ public class DefaultHttpService implements HttpService {
 
     @Override
     public void unregister(final String alias) {
-        servletRouter.unregisterService(alias);
+        servletRouter.unregisterServiceFromPath(alias);
     }
 
     @Override
diff --git a/osgi/src/main/java/com/ning/billing/osgi/http/DefaultServletRouter.java b/osgi/src/main/java/com/ning/billing/osgi/http/DefaultServletRouter.java
index e822259..30551cf 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/http/DefaultServletRouter.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/http/DefaultServletRouter.java
@@ -16,9 +16,9 @@
 
 package com.ning.billing.osgi.http;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 
 import javax.inject.Singleton;
 import javax.servlet.Servlet;
@@ -26,6 +26,7 @@ import javax.servlet.Servlet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.osgi.api.OSGIServiceDescriptor;
 import com.ning.billing.osgi.api.OSGIServiceRegistration;
 
 @Singleton
@@ -35,35 +36,60 @@ public class DefaultServletRouter implements OSGIServiceRegistration<Servlet> {
 
     // Internal Servlet routing table: map of plugin prefixes to servlet instances.
     // A plugin prefix can be /foo, /foo/bar, /foo/bar/baz, ... and is mounted on /plugins/<pluginPrefix>
-    private final Map<String, Servlet> pluginServlets = new ConcurrentHashMap<String, Servlet>();
+    private final Map<String, Servlet> pluginPathServlets = new HashMap<String, Servlet>();
+    private final Map<String, OSGIServiceDescriptor> pluginRegistrations = new HashMap<String, OSGIServiceDescriptor>();
 
     @Override
-    public void registerService(final String originalPathPrefix, final Servlet httpServlet) {
+    public void registerService(final OSGIServiceDescriptor desc, final Servlet httpServlet) {
         // Enforce each route to start with /
-        final String pathPrefix;
-        if (originalPathPrefix.charAt(0) != '/') {
-            pathPrefix = "/" + originalPathPrefix;
-        } else {
-            pathPrefix = originalPathPrefix;
-        }
+        final String pathPrefix = sanitizePathPrefix(desc.getServiceInfo());
         logger.info("Registering OSGI servlet at " + pathPrefix);
-        pluginServlets.put(pathPrefix, httpServlet);
+        synchronized (this) {
+            pluginPathServlets.put(pathPrefix, httpServlet);
+            pluginRegistrations.put(desc.getServiceName(), desc);
+        }
     }
 
-    @Override
-    public void unregisterService(final String pathPrefix) {
-        logger.info("Unregistering OSGI servlet at " + pathPrefix);
-        pluginServlets.remove(pathPrefix);
+    public void registerServiceFromPath(final String path, final Servlet httpServlet) {
+        pluginPathServlets.put(sanitizePathPrefix(path), httpServlet);
+    }
+
+
+        @Override
+    public void unregisterService(final String serviceName) {
+        synchronized (this) {
+            final OSGIServiceDescriptor desc = pluginRegistrations.get(serviceName);
+            if (desc != null) {
+                final String registeredPath = sanitizePathPrefix(desc.getServiceInfo());
+                pluginPathServlets.remove(registeredPath);
+                pluginRegistrations.remove(desc);
+                logger.info("Unregistering OSGI servlet " + desc.getServiceName() + " at path " + registeredPath);
+            }
+        }
+    }
+
+    public void unregisterServiceFromPath(final String path) {
+        pluginPathServlets.remove(sanitizePathPrefix(path));
     }
 
+
     @Override
-    public Servlet getServiceForPluginName(final String pathPrefix) {
-        return getServletForPathPrefix(pathPrefix);
+    public Servlet getServiceForName(final String serviceName) {
+        final OSGIServiceDescriptor desc = pluginRegistrations.get(serviceName);
+        if (desc == null) {
+            return null;
+        }
+        final String registeredPath = sanitizePathPrefix(desc.getServiceInfo());
+        return pluginPathServlets.get(registeredPath);
+    }
+
+    public Servlet getServiceForPath(final String path) {
+        return getServletForPathPrefix(path);
     }
 
     @Override
-    public Set<String> getAllServiceForPluginName() {
-        return pluginServlets.keySet();
+    public Set<String> getAllServices() {
+        return pluginPathServlets.keySet();
     }
 
     @Override
@@ -74,7 +100,7 @@ public class DefaultServletRouter implements OSGIServiceRegistration<Servlet> {
     // TODO PIERRE Naive implementation - we should rather switch to e.g. heap tree
     public String getPluginPrefixForPath(final String pathPrefix) {
         String bestMatch = null;
-        for (final String potentialMatch : pluginServlets.keySet()) {
+        for (final String potentialMatch : pluginPathServlets.keySet()) {
             if (pathPrefix.startsWith(potentialMatch) && (bestMatch == null || bestMatch.length() < potentialMatch.length())) {
                 bestMatch = potentialMatch;
             }
@@ -84,6 +110,17 @@ public class DefaultServletRouter implements OSGIServiceRegistration<Servlet> {
 
     private Servlet getServletForPathPrefix(final String pathPrefix) {
         final String bestMatch = getPluginPrefixForPath(pathPrefix);
-        return bestMatch == null ? null : pluginServlets.get(bestMatch);
+        return bestMatch == null ? null : pluginPathServlets.get(bestMatch);
+    }
+
+
+    private static final String sanitizePathPrefix(final String inputPath) {
+        final String pathPrefix;
+        if (inputPath.charAt(0) != '/') {
+            pathPrefix = "/" + inputPath;
+        } else {
+            pathPrefix = inputPath;
+        }
+        return pathPrefix;
     }
 }
diff --git a/osgi/src/main/java/com/ning/billing/osgi/http/OSGIServlet.java b/osgi/src/main/java/com/ning/billing/osgi/http/OSGIServlet.java
index a9af086..92c9b80 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/http/OSGIServlet.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/http/OSGIServlet.java
@@ -119,9 +119,9 @@ public class OSGIServlet extends HttpServlet {
         }
     }
 
-    private Servlet getPluginServlet(final String pluginName) {
-        if (pluginName != null) {
-            return servletRouter.getServiceForPluginName(pluginName);
+    private Servlet getPluginServlet(final String requestPath) {
+        if (requestPath != null) {
+            return servletRouter.getServiceForPath(requestPath);
         } else {
             return null;
         }
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 79f082b..715c120 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/KillbillActivator.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/KillbillActivator.java
@@ -16,60 +16,91 @@
 
 package com.ning.billing.osgi;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
 import java.util.List;
+import java.util.Observable;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.servlet.Servlet;
+import javax.sql.DataSource;
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceEvent;
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.http.HttpService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.ning.billing.osgi.api.OSGIKillbill;
 import com.ning.billing.osgi.api.OSGIPluginProperties;
+import com.ning.billing.osgi.api.OSGIServiceDescriptor;
 import com.ning.billing.osgi.api.OSGIServiceRegistration;
+import com.ning.billing.osgi.glue.DefaultOSGIModule;
 import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillRegistrar;
 
 import com.google.common.collect.ImmutableList;
 
 public class KillbillActivator implements BundleActivator, ServiceListener {
 
+    // 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);
+
     private final OSGIKillbill osgiKillbill;
     private final HttpService defaultHttpService;
+    private final DataSource dataSource;
+    private final KillbillEventObservable observable;
+    private final OSGIKillbillRegistrar registrar;
+
+
     private final List<OSGIServiceRegistration> allRegistrationHandlers;
 
-    private volatile ServiceRegistration osgiKillbillRegistration;
 
     private BundleContext context = null;
 
     @Inject
-    public KillbillActivator(final OSGIKillbill osgiKillbill,
+    public KillbillActivator(@Named(DefaultOSGIModule.OSGI_NAMED) final DataSource dataSource,
+                             final OSGIKillbill osgiKillbill,
                              final HttpService defaultHttpService,
+                             final KillbillEventObservable observable,
                              final OSGIServiceRegistration<Servlet> servletRouter,
                              final OSGIServiceRegistration<PaymentPluginApi> paymentProviderPluginRegistry) {
         this.osgiKillbill = osgiKillbill;
         this.defaultHttpService = defaultHttpService;
+        this.dataSource = dataSource;
+        this.observable = observable;
+        this.registrar = new OSGIKillbillRegistrar();
         this.allRegistrationHandlers = ImmutableList.<OSGIServiceRegistration>of(servletRouter, paymentProviderPluginRegistry);
+
     }
 
     @Override
     public void start(final BundleContext context) throws Exception {
+
         this.context = context;
+        final Dictionary props = new Hashtable();
+        props.put(OSGIPluginProperties.PLUGIN_NAME_PROP, "killbill");
+
+        observable.register();
+
+        registrar.registerService(context, OSGIKillbill.class, osgiKillbill, props);
+        registrar.registerService(context, HttpService.class, defaultHttpService, props);
+        registrar.registerService(context, Observable.class, observable, props);
+        registrar.registerService(context, DataSource.class, dataSource, props);
 
         context.addServiceListener(this);
-        registerServices(context);
     }
 
     @Override
     public void stop(final BundleContext context) throws Exception {
         this.context = null;
-
         context.removeServiceListener(this);
-        unregisterServices();
+        observable.unregister();
+        registrar.unregisterAll();
     }
 
     @Override
@@ -78,19 +109,25 @@ public class KillbillActivator implements BundleActivator, ServiceListener {
             // We are not initialized or uninterested
             return;
         }
+
+        final ServiceReference serviceReference = event.getServiceReference();
+        boolean processedServiceChange = false;
         for (OSGIServiceRegistration cur : allRegistrationHandlers) {
-            if (listenForServiceType(event, cur.getServiceType(), cur)) {
+            if (listenForServiceType(serviceReference, event.getType(), cur.getServiceType(), cur)) {
+                processedServiceChange = true;
                 break;
             }
         }
+        if (!processedServiceChange) {
+            logger.warn("Did not process ServiceEvent for {} ", serviceReference.getBundle().getSymbolicName());
+        }
     }
 
-    private <T> boolean listenForServiceType(final ServiceEvent event, final Class<T> claz, final OSGIServiceRegistration<T> registration) {
+    private <T> boolean listenForServiceType(final ServiceReference serviceReference, final int eventType, final Class<T> claz, final OSGIServiceRegistration<T> registration) {
         // Make sure we can retrieve the plugin name
-        final ServiceReference serviceReference = event.getServiceReference();
-        final String pluginName = (String) serviceReference.getProperty(OSGIPluginProperties.PLUGIN_NAME_PROP);
-        if (pluginName == null) {
-            // TODO STEPH logger ?
+        final String serviceName = (String) serviceReference.getProperty(OSGIPluginProperties.PLUGIN_NAME_PROP);
+        if (serviceName == null) {
+            logger.warn("Ignoring registered OSGI service {} with no {} property", claz.getName(), OSGIPluginProperties.PLUGIN_NAME_PROP);
             return true;
         }
 
@@ -100,30 +137,18 @@ public class KillbillActivator implements BundleActivator, ServiceListener {
             return false;
         }
 
-        switch (event.getType()) {
+        final String serviceInfo = (String) serviceReference.getProperty(OSGIPluginProperties.PLUGIN_SERVICE_INFO);
+        final OSGIServiceDescriptor desc =  new DefaultOSGIServiceDescriptor(serviceReference.getBundle().getSymbolicName(), serviceName, serviceInfo, claz.getName());
+        switch (eventType) {
             case ServiceEvent.REGISTERED:
-                registration.registerService(pluginName, theService);
+                registration.registerService(desc, theService);
                 break;
             case ServiceEvent.UNREGISTERING:
-                registration.unregisterService(pluginName);
+                registration.unregisterService(desc.getServiceName());
                 break;
             default:
                 break;
         }
-
         return true;
     }
-
-    private void registerServices(final BundleContext context) {
-        osgiKillbillRegistration = context.registerService(OSGIKillbill.class.getName(), osgiKillbill, null);
-
-        context.registerService(HttpService.class.getName(), defaultHttpService, null);
-    }
-
-    private void unregisterServices() {
-        if (osgiKillbillRegistration != null) {
-            osgiKillbillRegistration.unregister();
-            osgiKillbillRegistration = null;
-        }
-    }
 }
diff --git a/osgi/src/main/java/com/ning/billing/osgi/KillbillEventObservable.java b/osgi/src/main/java/com/ning/billing/osgi/KillbillEventObservable.java
new file mode 100644
index 0000000..14d7f4d
--- /dev/null
+++ b/osgi/src/main/java/com/ning/billing/osgi/KillbillEventObservable.java
@@ -0,0 +1,61 @@
+/*
+ * 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.util.Observable;
+
+import javax.inject.Inject;
+
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.beatrix.bus.api.ExtBusEvent;
+import com.ning.billing.beatrix.bus.api.ExternalBus;
+
+import com.google.common.eventbus.Subscribe;
+
+public class KillbillEventObservable extends Observable {
+
+
+    private Logger logger = LoggerFactory.getLogger(KillbillEventObservable.class);
+
+    private final ExternalBus externalBus;
+
+    @Inject
+    public KillbillEventObservable(final ExternalBus externalBus) {
+        this.externalBus = externalBus;
+    }
+
+    public void register() {
+        externalBus.register(this);
+    }
+
+    public void unregister() {
+        deleteObservers();
+        if (externalBus != null) {
+            externalBus.unregister(this);
+        }
+    }
+
+    @Subscribe
+    public void handleKillbillEvent(final ExtBusEvent killbillEvent) {
+        logger.debug("Received external event " + killbillEvent.toString());
+        setChanged();
+        notifyObservers(killbillEvent);
+    }
+}
diff --git a/osgi-bundles/bundles/pom.xml b/osgi-bundles/bundles/pom.xml
new file mode 100644
index 0000000..eaeeee5
--- /dev/null
+++ b/osgi-bundles/bundles/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.ning.billing</groupId>
+        <artifactId>killbill-osgi-all-bundles</artifactId>
+        <version>0.1.56-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-osgi-bundles</artifactId>
+    <name>Killbill billing platform: OSGI bundles</name>
+    <packaging>pom</packaging>
+    <modules>
+        <module>jruby</module>
+        <module>meter</module>
+        <module>webconsolebranding</module>
+    </modules>
+</project>
diff --git a/osgi-bundles/defaultbundles/pom.xml b/osgi-bundles/defaultbundles/pom.xml
index 8a01b71..ee54038 100644
--- a/osgi-bundles/defaultbundles/pom.xml
+++ b/osgi-bundles/defaultbundles/pom.xml
@@ -20,7 +20,7 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>com.ning.billing</groupId>
-        <artifactId>killbill-osgi-bundles</artifactId>
+        <artifactId>killbill-osgi-all-bundles</artifactId>
         <version>0.1.56-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
diff --git a/osgi-bundles/libs/killbill/pom.xml b/osgi-bundles/libs/killbill/pom.xml
new file mode 100644
index 0000000..47ef9c0
--- /dev/null
+++ b/osgi-bundles/libs/killbill/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.ning.billing</groupId>
+        <artifactId>killbill-osgi-lib-bundles</artifactId>
+        <version>0.1.56-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-osgi-bundles-lib-killbill</artifactId>
+    <name>Killbill billing platform: OSGI Killbill Library</name>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>osgi-over-slf4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
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
new file mode 100644
index 0000000..bd2056f
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/KillbillActivatorBase.java
@@ -0,0 +1,78 @@
+/*
+ * 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.killbill.osgi.libs.killbill;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillEventDispatcher.OSGIKillbillEventHandler;
+
+public abstract class KillbillActivatorBase implements BundleActivator {
+
+
+    protected OSGIKillbillAPI killbillAPI;
+    protected OSGIKillbillLogService logService;
+    protected OSGIKillbillRegistrar registrar;
+    protected OSGIKillbillDataSource dataSource;
+    protected OSGIKillbillEventDispatcher dispatcher;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+
+        // Tracked resource
+        killbillAPI = new OSGIKillbillAPI(context);
+        logService = new OSGIKillbillLogService(context);
+        dataSource = new OSGIKillbillDataSource(context);
+        dispatcher = new OSGIKillbillEventDispatcher(context);
+
+        // Registrar for bundle
+        registrar = new OSGIKillbillRegistrar();
+
+        // Killbill events
+        final OSGIKillbillEventHandler handler = getOSGIKillbillEventHandler();
+        if (handler != null) {
+            dispatcher.registerEventHandler(handler);
+        }
+    }
+
+    @Override
+    public void stop(final BundleContext context) throws Exception {
+
+        // Close trackers
+        killbillAPI.close();
+        dispatcher.close();
+        dataSource.close();
+        logService.close();
+
+        try {
+            // Remove Killbill event handler
+            final OSGIKillbillEventHandler handler = getOSGIKillbillEventHandler();
+            if (handler != null) {
+                dispatcher.unregisterEventHandler(handler);
+            }
+        } 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!");
+    }
+
+
+    public abstract OSGIKillbillEventHandler getOSGIKillbillEventHandler();
+}
diff --git a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillAPI.java b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillAPI.java
new file mode 100644
index 0000000..47ca336
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillAPI.java
@@ -0,0 +1,262 @@
+/*
+ * 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.killbill.osgi.libs.killbill;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.analytics.api.sanity.AnalyticsSanityApi;
+import com.ning.billing.analytics.api.user.AnalyticsUserApi;
+import com.ning.billing.catalog.api.CatalogUserApi;
+import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
+import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
+import com.ning.billing.entitlement.api.transfer.EntitlementTransferApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.invoice.api.InvoiceMigrationApi;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.osgi.api.OSGIKillbill;
+import com.ning.billing.osgi.api.config.PluginConfigServiceApi;
+import com.ning.billing.overdue.OverdueUserApi;
+import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.tenant.api.TenantUserApi;
+import com.ning.billing.usage.api.UsageUserApi;
+import com.ning.billing.util.api.AuditUserApi;
+import com.ning.billing.util.api.CustomFieldUserApi;
+import com.ning.billing.util.api.ExportUserApi;
+import com.ning.billing.util.api.TagUserApi;
+
+public class OSGIKillbillAPI extends OSGIKillbillLibraryBase implements OSGIKillbill {
+
+
+    private static final String KILLBILL_SERVICE_NAME = "com.ning.billing.osgi.api.OSGIKillbill";
+
+    private final ServiceTracker<OSGIKillbill, OSGIKillbill> killbillTracker;
+
+    public OSGIKillbillAPI(BundleContext context) {
+        killbillTracker = new ServiceTracker(context, KILLBILL_SERVICE_NAME, null);
+        killbillTracker.open();
+    }
+
+    public void close() {
+        if (killbillTracker != null) {
+            killbillTracker.close();
+        }
+    }
+
+    @Override
+    public AccountUserApi getAccountUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<AccountUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public AccountUserApi executeWithService(final OSGIKillbill service) {
+                return service.getAccountUserApi();
+            }
+        });
+    }
+
+    @Override
+    public AnalyticsSanityApi getAnalyticsSanityApi() {
+        return withServiceTracker(killbillTracker, new APICallback<AnalyticsSanityApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public AnalyticsSanityApi executeWithService(final OSGIKillbill service) {
+                return service.getAnalyticsSanityApi();
+            }
+        });
+    }
+
+    @Override
+    public AnalyticsUserApi getAnalyticsUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<AnalyticsUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public AnalyticsUserApi executeWithService(final OSGIKillbill service) {
+                return service.getAnalyticsUserApi();
+            }
+        });
+
+    }
+
+    @Override
+    public CatalogUserApi getCatalogUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<CatalogUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public CatalogUserApi executeWithService(final OSGIKillbill service) {
+                return service.getCatalogUserApi();
+            }
+        });
+    }
+
+    @Override
+    public EntitlementMigrationApi getEntitlementMigrationApi() {
+        return withServiceTracker(killbillTracker, new APICallback<EntitlementMigrationApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public EntitlementMigrationApi executeWithService(final OSGIKillbill service) {
+                return service.getEntitlementMigrationApi();
+            }
+        });
+    }
+
+    @Override
+    public EntitlementTimelineApi getEntitlementTimelineApi() {
+        return withServiceTracker(killbillTracker, new APICallback<EntitlementTimelineApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public EntitlementTimelineApi executeWithService(final OSGIKillbill service) {
+                return service.getEntitlementTimelineApi();
+            }
+        });
+    }
+
+    @Override
+    public EntitlementTransferApi getEntitlementTransferApi() {
+        return withServiceTracker(killbillTracker, new APICallback<EntitlementTransferApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public EntitlementTransferApi executeWithService(final OSGIKillbill service) {
+                return service.getEntitlementTransferApi();
+            }
+        });
+    }
+
+    @Override
+    public EntitlementUserApi getEntitlementUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<EntitlementUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public EntitlementUserApi executeWithService(final OSGIKillbill service) {
+                return service.getEntitlementUserApi();
+            }
+        });
+    }
+
+    @Override
+    public InvoiceMigrationApi getInvoiceMigrationApi() {
+        return withServiceTracker(killbillTracker, new APICallback<InvoiceMigrationApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public InvoiceMigrationApi executeWithService(final OSGIKillbill service) {
+                return service.getInvoiceMigrationApi();
+            }
+        });
+    }
+
+    @Override
+    public InvoicePaymentApi getInvoicePaymentApi() {
+        return withServiceTracker(killbillTracker, new APICallback<InvoicePaymentApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public InvoicePaymentApi executeWithService(final OSGIKillbill service) {
+                return service.getInvoicePaymentApi();
+            }
+        });
+    }
+
+    @Override
+    public InvoiceUserApi getInvoiceUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<InvoiceUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public InvoiceUserApi executeWithService(final OSGIKillbill service) {
+                return service.getInvoiceUserApi();
+            }
+        });
+    }
+
+    @Override
+    public OverdueUserApi getOverdueUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<OverdueUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public OverdueUserApi executeWithService(final OSGIKillbill service) {
+                return service.getOverdueUserApi();
+            }
+        });
+    }
+
+    @Override
+    public PaymentApi getPaymentApi() {
+        return withServiceTracker(killbillTracker, new APICallback<PaymentApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public PaymentApi executeWithService(final OSGIKillbill service) {
+                return service.getPaymentApi();
+            }
+        });
+    }
+
+    @Override
+    public TenantUserApi getTenantUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<TenantUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public TenantUserApi executeWithService(final OSGIKillbill service) {
+                return service.getTenantUserApi();
+            }
+        });
+    }
+
+    @Override
+    public UsageUserApi getUsageUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<UsageUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public UsageUserApi executeWithService(final OSGIKillbill service) {
+                return service.getUsageUserApi();
+            }
+        });
+    }
+
+    @Override
+    public AuditUserApi getAuditUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<AuditUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public AuditUserApi executeWithService(final OSGIKillbill service) {
+                return service.getAuditUserApi();
+            }
+        });
+    }
+
+    @Override
+    public CustomFieldUserApi getCustomFieldUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<CustomFieldUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public CustomFieldUserApi executeWithService(final OSGIKillbill service) {
+                return service.getCustomFieldUserApi();
+            }
+        });
+    }
+
+    @Override
+    public ExportUserApi getExportUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<ExportUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public ExportUserApi executeWithService(final OSGIKillbill service) {
+                return service.getExportUserApi();
+            }
+        });
+    }
+
+    @Override
+    public TagUserApi getTagUserApi() {
+        return withServiceTracker(killbillTracker, new APICallback<TagUserApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public TagUserApi executeWithService(final OSGIKillbill service) {
+                return service.getTagUserApi();
+            }
+        });
+    }
+
+    @Override
+    public PluginConfigServiceApi getPluginConfigServiceApi() {
+        return withServiceTracker(killbillTracker, new APICallback<PluginConfigServiceApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public PluginConfigServiceApi executeWithService(final OSGIKillbill service) {
+                return service.getPluginConfigServiceApi();
+            }
+        });
+    }
+}
diff --git a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillDataSource.java b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillDataSource.java
new file mode 100644
index 0000000..6e1c671
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillDataSource.java
@@ -0,0 +1,50 @@
+/*
+ * 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.killbill.osgi.libs.killbill;
+
+import javax.sql.DataSource;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class OSGIKillbillDataSource extends OSGIKillbillLibraryBase {
+
+    private static final String DATASOURCE_SERVICE_NAME = "javax.sql.DataSource";
+
+    private final ServiceTracker<DataSource, DataSource> dataSourceTracker;
+
+
+    public OSGIKillbillDataSource(BundleContext context) {
+        dataSourceTracker = new ServiceTracker(context, DATASOURCE_SERVICE_NAME, null);
+        dataSourceTracker.open();
+    }
+
+    public void close() {
+        if (dataSourceTracker != null) {
+            dataSourceTracker.close();
+        }
+    }
+
+    public DataSource getDataSource() {
+        return withServiceTracker(dataSourceTracker, new APICallback<DataSource, DataSource>(DATASOURCE_SERVICE_NAME) {
+            @Override
+            public DataSource executeWithService(final DataSource service) {
+                return dataSourceTracker.getService();
+            }
+        });
+    }
+}
diff --git a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillEventDispatcher.java b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillEventDispatcher.java
new file mode 100644
index 0000000..1bdf9fe
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillEventDispatcher.java
@@ -0,0 +1,95 @@
+/*
+ * 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.killbill.osgi.libs.killbill;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Observable;
+import java.util.Observer;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+import com.ning.billing.beatrix.bus.api.ExtBusEvent;
+
+public class OSGIKillbillEventDispatcher extends OSGIKillbillLibraryBase {
+
+    private static final String OBSERVABLE_SERVICE_NAME = "java.util.Observable";
+
+    private final ServiceTracker<Observable, Observable> observableTracker;
+
+
+    private final Map<OSGIKillbillEventHandler, Observer> handlerToObserver;
+
+    public OSGIKillbillEventDispatcher(BundleContext context) {
+        handlerToObserver = new HashMap<OSGIKillbillEventHandler, Observer>();
+        observableTracker = new ServiceTracker(context, OBSERVABLE_SERVICE_NAME, null);
+        observableTracker.open();
+    }
+
+    public void close() {
+        if (observableTracker != null) {
+            observableTracker.close();
+        }
+        handlerToObserver.clear();
+    }
+
+    public void registerEventHandler(final OSGIKillbillEventHandler handler) {
+
+        withServiceTracker(observableTracker, new APICallback<Void, Observable>(OBSERVABLE_SERVICE_NAME) {
+            @Override
+            public Void executeWithService(final Observable service) {
+
+                final Observer observer = new Observer() {
+                    @Override
+                    public void update(final Observable o, final Object arg) {
+                        if (!(arg instanceof ExtBusEvent)) {
+                            // TODO STEPH or should we throw because that should not happen
+                            return;
+                        }
+                        handler.handleKillbillEvent((ExtBusEvent) arg);
+                    }
+                };
+                handlerToObserver.put(handler, observer);
+                service.addObserver(observer);
+                return null;
+            }
+        });
+    }
+
+    public void unregisterEventHandler(final OSGIKillbillEventHandler handler) {
+        withServiceTracker(observableTracker, new APICallback<Void, Observable>(OBSERVABLE_SERVICE_NAME) {
+            @Override
+            public Void executeWithService(final Observable service) {
+
+                final Observer observer = handlerToObserver.get(handler);
+                if (observer != null) {
+                    service.deleteObserver(observer);
+                    handlerToObserver.remove(handler);
+                }
+                return null;
+            }
+        });
+
+    }
+
+    public interface OSGIKillbillEventHandler {
+
+        public void handleKillbillEvent(final ExtBusEvent killbillEvent);
+    }
+
+}
diff --git a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillLibraryBase.java b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillLibraryBase.java
new file mode 100644
index 0000000..ce86b45
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillLibraryBase.java
@@ -0,0 +1,53 @@
+/*
+ * 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.killbill.osgi.libs.killbill;
+
+import org.osgi.util.tracker.ServiceTracker;
+
+public abstract class OSGIKillbillLibraryBase {
+
+
+    public OSGIKillbillLibraryBase() {
+
+    }
+
+    public abstract void close();
+
+
+    protected abstract class APICallback<API, T> {
+
+        private final String serviceName;
+
+        protected APICallback(final String serviceName) {
+            this.serviceName = serviceName;
+        }
+
+        public abstract API executeWithService(T service);
+
+        protected API executeWithNoService() {
+            throw new OSGIServiceNotAvailable(serviceName);
+        }
+    }
+
+    protected <API, S, T> API withServiceTracker(ServiceTracker<S, T> t, APICallback<API, T> cb) {
+        T service = t.getService();
+        if (service == null) {
+            return cb.executeWithNoService();
+        }
+        return cb.executeWithService(service);
+    }
+}
diff --git a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillRegistrar.java b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillRegistrar.java
new file mode 100644
index 0000000..7168b95
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillRegistrar.java
@@ -0,0 +1,52 @@
+/*
+ * 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.killbill.osgi.libs.killbill;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class OSGIKillbillRegistrar {
+
+    private final Map<String, ServiceRegistration> serviceRegistrations;
+
+    public OSGIKillbillRegistrar() {
+        this.serviceRegistrations = new HashMap<String, ServiceRegistration>();
+    }
+
+    public <S, T extends S> void registerService(final BundleContext context, final Class<S> svcClass, final S service, final Dictionary props) {
+        ServiceRegistration svcRegistration = context.registerService(svcClass.getName(), service, props);
+        serviceRegistrations.put(svcClass.getName(), svcRegistration);
+    }
+
+    public <S> void unregisterService(final Class<S> svcClass) {
+        ServiceRegistration svc = serviceRegistrations.remove(svcClass.getName());
+        if (svc != null) {
+            svc.unregister();
+        }
+    }
+
+    public void unregisterAll() {
+        for (ServiceRegistration cur : serviceRegistrations.values()) {
+            cur.unregister();
+        }
+        serviceRegistrations.clear();
+    }
+}
diff --git a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIServiceNotAvailable.java b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIServiceNotAvailable.java
new file mode 100644
index 0000000..4a86243
--- /dev/null
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIServiceNotAvailable.java
@@ -0,0 +1,38 @@
+/*
+ * 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.killbill.osgi.libs.killbill;
+
+public class OSGIServiceNotAvailable extends RuntimeException  {
+
+    private static final String FORMAT_SERVICE_NOT_AVAILABLE = "OSGI service %s is not available";
+
+    public OSGIServiceNotAvailable(String serviceName) {
+        super(toFormat(serviceName));
+    }
+
+    public OSGIServiceNotAvailable(String serviceName, Throwable cause) {
+        super(toFormat(serviceName), cause);
+    }
+
+    public OSGIServiceNotAvailable(Throwable cause) {
+        super(cause);
+    }
+
+    private static String toFormat(String serviceName) {
+        return String.format(FORMAT_SERVICE_NOT_AVAILABLE, serviceName);
+    }
+}
diff --git a/osgi-bundles/libs/pom.xml b/osgi-bundles/libs/pom.xml
new file mode 100644
index 0000000..219e436
--- /dev/null
+++ b/osgi-bundles/libs/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.ning.billing</groupId>
+        <artifactId>killbill-osgi-all-bundles</artifactId>
+        <version>0.1.56-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-osgi-lib-bundles</artifactId>
+    <name>Killbill billing platform: OSGI library bundles</name>
+    <packaging>pom</packaging>
+    <modules>
+      <module>killbill</module>
+    </modules>
+</project>
diff --git a/osgi-bundles/pom.xml b/osgi-bundles/pom.xml
index dc984c2..3c5e4f2 100644
--- a/osgi-bundles/pom.xml
+++ b/osgi-bundles/pom.xml
@@ -23,15 +23,13 @@
         <version>0.1.56-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
-    <artifactId>killbill-osgi-bundles</artifactId>
-    <name>Killbill billing platform: OSGI bundles</name>
+    <artifactId>killbill-osgi-all-bundles</artifactId>
+    <name>Killbill billing platform: OSGI ALL bundles</name>
     <packaging>pom</packaging>
     <modules>
-        <module>hello</module>
-        <module>jruby</module>
-        <module>meter</module>
-        <module>test</module>
-        <module>webconsolebranding</module>
+        <module>libs</module>
+        <module>bundles</module>
+        <module>tests</module>
         <module>defaultbundles</module>
     </modules>
 </project>
diff --git a/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/PaymentActivator.java b/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/PaymentActivator.java
new file mode 100644
index 0000000..00d2113
--- /dev/null
+++ b/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/PaymentActivator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.bundles.test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.BundleContext;
+
+import com.ning.billing.osgi.api.OSGIPluginProperties;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiWithTestControl;
+import com.ning.killbill.osgi.libs.killbill.KillbillActivatorBase;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillEventDispatcher.OSGIKillbillEventHandler;
+
+/**
+ * Test class used by Payment tests-- to test fake OSGI payment bundle
+ */
+public class PaymentActivator extends KillbillActivatorBase {
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+
+        final String bundleName = context.getBundle().getSymbolicName();
+        System.out.println("PaymentActivator starting bundle = " + bundleName);
+
+        super.start(context);
+        registerPaymentApi(context);
+    }
+
+    @Override
+    public void stop(final BundleContext context) throws Exception {
+        super.stop(context);
+        System.out.println("Good bye world from PaymentActivator!");
+    }
+
+    @Override
+    public OSGIKillbillEventHandler getOSGIKillbillEventHandler() {
+        return null;
+    }
+
+    private void registerPaymentApi(final BundleContext context) {
+
+        final Dictionary props = new Hashtable();
+        // Same name the beatrix tests expect when using that payment plugin
+        props.put(OSGIPluginProperties.PLUGIN_NAME_PROP, "osgiPaymentPlugin");
+        registrar.registerService(context, PaymentPluginApiWithTestControl.class, new TestPaymentPluginApi("test"), props);
+    }
+}
diff --git a/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java b/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
new file mode 100644
index 0000000..b3d4fb6
--- /dev/null
+++ b/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
@@ -0,0 +1,195 @@
+/*
+ * 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.bundles.test;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.payment.api.PaymentMethodPlugin;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
+import com.ning.billing.payment.plugin.api.PaymentMethodInfoPlugin;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiWithTestControl;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.TenantContext;
+
+public class TestPaymentPluginApi implements PaymentPluginApiWithTestControl {
+
+    private final String name;
+
+    private PaymentPluginApiException paymentPluginApiExceptionOnNextCalls;
+    private RuntimeException runtimeExceptionOnNextCalls;
+
+    public TestPaymentPluginApi(final String name) {
+        this.name = name;
+        resetToNormalbehavior();
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public PaymentInfoPlugin processPayment(final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
+        return withRuntimeCheckForExceptions(new PaymentInfoPlugin() {
+            @Override
+            public BigDecimal getAmount() {
+                return amount;
+            }
+            @Override
+            public DateTime getCreatedDate() {
+                return new DateTime();
+            }
+            @Override
+            public DateTime getEffectiveDate() {
+                return new DateTime();
+            }
+            @Override
+            public PaymentPluginStatus getStatus() {
+                return PaymentPluginStatus.PROCESSED;
+            }
+            @Override
+            public String getGatewayError() {
+                return null;
+            }
+            @Override
+            public String getGatewayErrorCode() {
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public PaymentInfoPlugin getPaymentInfo(final UUID kbPaymentId, final TenantContext context) throws PaymentPluginApiException {
+
+        final BigDecimal someAmount = new BigDecimal("12.45");
+        return withRuntimeCheckForExceptions(new PaymentInfoPlugin() {
+            @Override
+            public BigDecimal getAmount() {
+                return someAmount;
+            }
+            @Override
+            public DateTime getCreatedDate() {
+                return new DateTime();
+            }
+            @Override
+            public DateTime getEffectiveDate() {
+                return new DateTime();
+            }
+            @Override
+            public PaymentPluginStatus getStatus() {
+                return PaymentPluginStatus.PROCESSED;
+            }
+            @Override
+            public String getGatewayError() {
+                return null;
+            }
+            @Override
+            public String getGatewayErrorCode() {
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public RefundInfoPlugin processRefund(final UUID kbPaymentId, final BigDecimal refundAmount, final CallContext context) throws PaymentPluginApiException {
+
+        final BigDecimal someAmount = new BigDecimal("12.45");
+        return withRuntimeCheckForExceptions(new RefundInfoPlugin() {
+            @Override
+            public BigDecimal getAmount() {
+                return null;
+            }
+            @Override
+            public DateTime getCreatedDate() {
+                return null;
+            }
+            @Override
+            public DateTime getEffectiveDate() {
+                return null;
+            }
+            @Override
+            public RefundPluginStatus getStatus() {
+                return null;
+            }
+            @Override
+            public String getGatewayError() {
+                return null;
+            }
+            @Override
+            public String getGatewayErrorCode() {
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public void addPaymentMethod(final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
+    }
+
+    @Override
+    public void deletePaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
+    }
+
+    @Override
+    public void setDefaultPaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
+    }
+
+    @Override
+    public List<PaymentMethodInfoPlugin> getPaymentMethods(final UUID kbAccountId, final boolean refreshFromGateway, final CallContext context) throws PaymentPluginApiException {
+        return null;
+    }
+
+    @Override
+    public void resetPaymentMethods(final List<PaymentMethodInfoPlugin> paymentMethods) throws PaymentPluginApiException {
+    }
+
+
+    private <T> T withRuntimeCheckForExceptions(final T result) throws PaymentPluginApiException {
+        if (paymentPluginApiExceptionOnNextCalls != null) {
+            throw paymentPluginApiExceptionOnNextCalls;
+
+        } else if (runtimeExceptionOnNextCalls != null) {
+            throw runtimeExceptionOnNextCalls;
+        } else {
+            return result;
+        }
+    }
+
+    @Override
+    public void setPaymentPluginApiExceptionOnNextCalls(final PaymentPluginApiException e) {
+        resetToNormalbehavior();
+        paymentPluginApiExceptionOnNextCalls = e;
+    }
+
+    @Override
+    public void setPaymentRuntimeExceptionOnNextCalls(final RuntimeException e) {
+        resetToNormalbehavior();
+        runtimeExceptionOnNextCalls = e;
+    }
+
+    @Override
+    public void resetToNormalbehavior() {
+        paymentPluginApiExceptionOnNextCalls = null;
+        runtimeExceptionOnNextCalls = null;
+    }
+}
diff --git a/osgi-bundles/tests/payment/src/test/resources/ddl_test.sql b/osgi-bundles/tests/payment/src/test/resources/ddl_test.sql
new file mode 100644
index 0000000..e4bfa5d
--- /dev/null
+++ b/osgi-bundles/tests/payment/src/test/resources/ddl_test.sql
@@ -0,0 +1,10 @@
+/*! SET storage_engine=INNODB */;
+
+DROP TABLE IF EXISTS test_bundle;
+CREATE TABLE test_bundle (
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    is_started bool DEFAULT false,
+    is_logged bool DEFAULT false,
+    external_key varchar(128) NULL
+    PRIMARY KEY(record_id)
+);
diff --git a/osgi-bundles/tests/pom.xml b/osgi-bundles/tests/pom.xml
new file mode 100644
index 0000000..79083cf
--- /dev/null
+++ b/osgi-bundles/tests/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.ning.billing</groupId>
+        <artifactId>killbill-osgi-all-bundles</artifactId>
+        <version>0.1.56-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-osgi-test-bundles</artifactId>
+    <name>Killbill billing platform: OSGI Test bundles</name>
+    <packaging>pom</packaging>
+    <modules>
+        <module>beatrix</module>
+        <module>payment</module>
+    </modules>
+</project>
diff --git a/osgi-bundles/tests/src/assemble/assembly.xml b/osgi-bundles/tests/src/assemble/assembly.xml
new file mode 100644
index 0000000..44d5bf3
--- /dev/null
+++ b/osgi-bundles/tests/src/assemble/assembly.xml
@@ -0,0 +1,58 @@
+<!--
+            POM
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.3</version>
+                <configuration>
+                    <tarLongFileMode>gnu</tarLongFileMode>
+                    <appendAssemblyId>false</appendAssemblyId>
+                    <descriptors>
+                        <descriptor>src/assemble/assembly.xml</descriptor>
+                    </descriptors>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>assemble-bundle-test</id>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <phase>package</phase>
+                    </execution>
+                </executions>
+            </plugin>
+
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+    <id>xoxo-test</id>
+    <formats>
+        <format>jar</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory>target/classes</directory>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0755</fileMode>
+        </fileSet>
+    </fileSets>
+
+    <dependencySets>
+        <dependencySet>
+
+            <scope>compile</scope>
+            <outputFileNameMapping>
+                ${artifact.groupId}-${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}
+            </outputFileNameMapping>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>/</outputDirectory>
+            <unpack>true</unpack>
+            <fileMode>0644</fileMode>
+        </dependencySet>
+
+    </dependencySets>
+
+</assembly>
diff --git a/osgi-bundles/tests/src/test/resources/ddl_test.sql b/osgi-bundles/tests/src/test/resources/ddl_test.sql
new file mode 100644
index 0000000..e4bfa5d
--- /dev/null
+++ b/osgi-bundles/tests/src/test/resources/ddl_test.sql
@@ -0,0 +1,10 @@
+/*! SET storage_engine=INNODB */;
+
+DROP TABLE IF EXISTS test_bundle;
+CREATE TABLE test_bundle (
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    is_started bool DEFAULT false,
+    is_logged bool DEFAULT false,
+    external_key varchar(128) NULL
+    PRIMARY KEY(record_id)
+);
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
index ab294d9..dd48514 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
@@ -74,7 +74,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
     }
 
     public Set<String> getAvailablePlugins() {
-        return pluginRegistry.getAllServiceForPluginName();
+        return pluginRegistry.getAllServices();
     }
 
     public UUID addPaymentMethod(final String pluginName, final Account account,
@@ -88,7 +88,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
                 PaymentMethod pm = null;
                 PaymentPluginApi pluginApi = null;
                 try {
-                    pluginApi = pluginRegistry.getServiceForPluginName(pluginName);
+                    pluginApi = pluginRegistry.getServiceForName(pluginName);
                     pm = new DefaultPaymentMethod(account.getId(), pluginName, paymentMethodProps);
                     pluginApi.addPaymentMethod(pm.getId(), paymentMethodProps, setDefault, context.toCallContext());
                     final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(pm.getId(), pm.getCreatedDate(), pm.getUpdatedDate(),
@@ -157,7 +157,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
             addPaymentMethod(ExternalPaymentProviderPlugin.PLUGIN_NAME, account, false, props, context);
         }
 
-        return (ExternalPaymentProviderPlugin) pluginRegistry.getServiceForPluginName(ExternalPaymentProviderPlugin.PLUGIN_NAME);
+        return (ExternalPaymentProviderPlugin) pluginRegistry.getServiceForName(ExternalPaymentProviderPlugin.PLUGIN_NAME);
     }
 
     private List<PaymentMethod> getPaymentMethodInternal(final List<PaymentMethodModelDao> paymentMethodModels, final UUID accountId,
@@ -244,7 +244,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
         if (paymentMethod == null) {
             throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
         }
-        return pluginRegistry.getServiceForPluginName(paymentMethod.getPluginName());
+        return pluginRegistry.getServiceForName(paymentMethod.getPluginName());
     }
 
     /**
@@ -262,7 +262,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
 
 
         // Don't hold the account lock while fetching the payment methods from the gateway as those could change anyway
-        final PaymentPluginApi pluginApi = pluginRegistry.getServiceForPluginName(pluginName);
+        final PaymentPluginApi pluginApi = pluginRegistry.getServiceForName(pluginName);
         final List<PaymentMethodInfoPlugin> pluginPms;
         try {
             pluginPms = pluginApi.getPaymentMethods(account.getId(), true, context.toCallContext());
diff --git a/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java b/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
index cd345fc..e3366aa 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
@@ -110,7 +110,7 @@ public abstract class ProcessorBase {
             log.error("PaymentMethod dpes not exist", paymentMethodId);
             throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
         }
-        return pluginRegistry.getServiceForPluginName(methodDao.getPluginName());
+        return pluginRegistry.getServiceForName(methodDao.getPluginName());
     }
 
     protected PaymentPluginApi getPaymentProviderPlugin(final String accountKey, final InternalTenantContext context)
@@ -121,7 +121,7 @@ public abstract class ProcessorBase {
             final Account account = accountInternalApi.getAccountByKey(accountKey, context);
             return getPaymentProviderPlugin(account, context);
         }
-        return pluginRegistry.getServiceForPluginName(paymentProviderName);
+        return pluginRegistry.getServiceForName(paymentProviderName);
     }
 
     protected PaymentPluginApi getPaymentProviderPlugin(final Account account, final InternalTenantContext context) throws PaymentApiException {
diff --git a/payment/src/main/java/com/ning/billing/payment/glue/DefaultPaymentProviderPluginRegistryProvider.java b/payment/src/main/java/com/ning/billing/payment/glue/DefaultPaymentProviderPluginRegistryProvider.java
index 4bc2349..ed47264 100644
--- a/payment/src/main/java/com/ning/billing/payment/glue/DefaultPaymentProviderPluginRegistryProvider.java
+++ b/payment/src/main/java/com/ning/billing/payment/glue/DefaultPaymentProviderPluginRegistryProvider.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.payment.glue;
 
+import com.ning.billing.osgi.api.OSGIServiceDescriptor;
 import com.ning.billing.osgi.api.OSGIServiceRegistration;
 import com.ning.billing.payment.plugin.api.PaymentPluginApi;
 import com.ning.billing.util.config.PaymentConfig;
@@ -41,7 +42,25 @@ public class DefaultPaymentProviderPluginRegistryProvider implements Provider<OS
         final DefaultPaymentProviderPluginRegistry pluginRegistry = new DefaultPaymentProviderPluginRegistry(paymentConfig);
 
         // Make the external payment provider plugin available by default
-        pluginRegistry.registerService(ExternalPaymentProviderPlugin.PLUGIN_NAME, externalPaymentProviderPlugin);
+        final OSGIServiceDescriptor desc = new OSGIServiceDescriptor() {
+            @Override
+            public String getPluginSymbolicName() {
+                return null;
+            }
+            @Override
+            public String getServiceName() {
+                return ExternalPaymentProviderPlugin.PLUGIN_NAME;
+            }
+            @Override
+            public String getServiceInfo() {
+                return null;
+            }
+            @Override
+            public String getServiceType() {
+                return null;
+            }
+        };
+        pluginRegistry.registerService(desc, externalPaymentProviderPlugin);
 
         return pluginRegistry;
     }
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java b/payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java
index 0bfc1b1..6825980 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import com.ning.billing.osgi.api.OSGIServiceDescriptor;
 import com.ning.billing.osgi.api.OSGIServiceRegistration;
 import com.ning.billing.payment.plugin.api.PaymentPluginApi;
 import com.ning.billing.util.config.PaymentConfig;
@@ -39,17 +40,17 @@ public class DefaultPaymentProviderPluginRegistry implements OSGIServiceRegistra
 
 
     @Override
-    public void registerService(final String pluginName, final PaymentPluginApi service) {
-        pluginsByName.put(pluginName.toLowerCase(), service);
+    public void registerService(final OSGIServiceDescriptor desc, final PaymentPluginApi service) {
+        pluginsByName.put(desc.getServiceName().toLowerCase(), service);
     }
 
     @Override
-    public void unregisterService(final String pluginName) {
-        pluginsByName.remove(pluginName.toLowerCase());
+    public void unregisterService(final String serviceName) {
+        pluginsByName.remove(serviceName.toLowerCase());
     }
 
     @Override
-    public PaymentPluginApi getServiceForPluginName(final String name) {
+    public PaymentPluginApi getServiceForName(final String name) {
         final PaymentPluginApi plugin = pluginsByName.get((Strings.emptyToNull(name) == null ? defaultPlugin : name).toLowerCase());
 
         if (plugin == null) {
@@ -60,7 +61,7 @@ public class DefaultPaymentProviderPluginRegistry implements OSGIServiceRegistra
     }
 
     @Override
-    public Set<String> getAllServiceForPluginName() {
+    public Set<String> getAllServices() {
         return pluginsByName.keySet();
     }
 
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/ExternalPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/ExternalPaymentProviderPlugin.java
index 0262bce..ac621ba 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/ExternalPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/ExternalPaymentProviderPlugin.java
@@ -16,11 +16,6 @@
 
 package com.ning.billing.payment.provider;
 
-import java.util.List;
-import java.util.UUID;
-
-import com.ning.billing.payment.plugin.api.PaymentMethodInfoPlugin;
-import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 
 import com.google.inject.Inject;
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPluginProvider.java b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPluginProvider.java
index 8bd3830..2a9cf4c 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPluginProvider.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPluginProvider.java
@@ -19,6 +19,7 @@ package com.ning.billing.payment.provider;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
+import com.ning.billing.osgi.api.OSGIServiceDescriptor;
 import com.ning.billing.osgi.api.OSGIServiceRegistration;
 import com.ning.billing.payment.plugin.api.PaymentPluginApi;
 import com.ning.billing.util.clock.Clock;
@@ -43,9 +44,27 @@ public class NoOpPaymentProviderPluginProvider implements Provider<DefaultNoOpPa
 
     @Override
     public DefaultNoOpPaymentProviderPlugin get() {
-        final DefaultNoOpPaymentProviderPlugin plugin = new DefaultNoOpPaymentProviderPlugin(clock);
 
-        registry.registerService(instanceName, plugin);
+        final DefaultNoOpPaymentProviderPlugin plugin = new DefaultNoOpPaymentProviderPlugin(clock);
+        final OSGIServiceDescriptor desc = new OSGIServiceDescriptor() {
+            @Override
+            public String getPluginSymbolicName() {
+                return null;
+            }
+            @Override
+            public String getServiceName() {
+                return instanceName;
+            }
+            @Override
+            public String getServiceInfo() {
+                return null;
+            }
+            @Override
+            public String getServiceType() {
+                return null;
+            }
+        };
+        registry.registerService(desc, plugin);
         return plugin;
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java b/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java
new file mode 100644
index 0000000..8d4f602
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java
@@ -0,0 +1,107 @@
+/*
+ * 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.payment.core;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.payment.PaymentTestSuiteWithEmbeddedDB;
+import com.ning.billing.payment.TestPaymentHelper;
+import com.ning.billing.payment.api.PaymentMethod;
+import com.ning.billing.payment.dao.PaymentMethodModelDao;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
+
+public class TestPaymentMethodProcessorRefreshWithDB extends PaymentTestSuiteWithEmbeddedDB {
+
+
+    @BeforeMethod(groups = "slow")
+    public void beforeMethod() throws Exception {
+        super.beforeMethod();
+        getPluginApi().resetPaymentMethods(null);
+    }
+
+    @Test(groups = "slow")
+    public void testRefreshWithNewPaymentMethod() throws Exception {
+
+        final Account account = testHelper.createTestAccount("foo@bar.com", true);
+        Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, callContext).size(), 1);
+        final UUID existingPMId = account.getPaymentMethodId();
+
+        // Add new payment in plugin directly
+        final UUID newPmId = UUID.randomUUID();
+        getPluginApi().addPaymentMethod(newPmId, null, false, callContext);
+
+        // Verify that the refresh does indeed show 2 PMs
+        final List<PaymentMethod> methods = paymentMethodProcessor.refreshPaymentMethods(TestPaymentHelper.PLUGIN_TEST_NAME, account, internalCallContext);
+        Assert.assertEquals(methods.size(), 2);
+        checkPaymentMethodExistsWithStatus(methods, existingPMId, true);
+        checkPaymentMethodExistsWithStatus(methods, newPmId, true);
+    }
+
+
+    @Test(groups = "slow")
+    public void testRefreshWithDeletedPaymentMethod() throws Exception {
+
+        final Account account = testHelper.createTestAccount("super@bar.com", true);
+        Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, callContext).size(), 1);
+        final UUID firstPmId = account.getPaymentMethodId();
+
+        final UUID secondPmId = paymentApi.addPaymentMethod(TestPaymentHelper.PLUGIN_TEST_NAME, account, true, new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), false, null), callContext);
+        Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, callContext).size(), 2);
+        Assert.assertEquals(paymentApi.getPaymentMethods(account, callContext).size(), 2);
+
+        // Remove second PM from plugin
+        getPluginApi().deletePaymentMethod(secondPmId, callContext);
+        Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, callContext).size(), 1);
+        Assert.assertEquals(paymentApi.getPaymentMethods(account, callContext).size(), 2);
+
+        // Verify that the refresh sees that PM as being deleted now
+        final List<PaymentMethod> methods = paymentMethodProcessor.refreshPaymentMethods(TestPaymentHelper.PLUGIN_TEST_NAME, account, internalCallContext);
+        Assert.assertEquals(methods.size(), 1);
+        checkPaymentMethodExistsWithStatus(methods, firstPmId, true);
+
+        PaymentMethodModelDao deletedPMModel =  paymentDao.getPaymentMethodIncludedDeleted(secondPmId, internalCallContext);
+        Assert.assertNotNull(deletedPMModel);
+        Assert.assertFalse(deletedPMModel.isActive());
+    }
+
+
+    private void checkPaymentMethodExistsWithStatus(final List<PaymentMethod> methods, UUID expectedPaymentMethodId, boolean expectedActive) {
+        PaymentMethod foundPM = null;
+        for (PaymentMethod cur : methods) {
+            if (cur.getId().equals(expectedPaymentMethodId)) {
+                foundPM = cur;
+                break;
+            }
+        }
+        Assert.assertNotNull(foundPM);
+        Assert.assertEquals(foundPM.isActive().booleanValue(), expectedActive);
+    }
+
+
+    private PaymentPluginApi getPluginApi() {
+        final PaymentPluginApi pluginApi = registry.getServiceForName(TestPaymentHelper.PLUGIN_TEST_NAME);
+        Assert.assertNotNull(pluginApi);
+        return pluginApi;
+    }
+}
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
index cbda487..a9b754f 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -16,14 +16,156 @@
 
 package com.ning.billing.payment.provider;
 
+import java.math.BigDecimal;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Multimap;
 import com.google.inject.Inject;
+
+import com.ning.billing.payment.api.PaymentMethodPlugin;
+import com.ning.billing.payment.plugin.api.NoOpPaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin.PaymentPluginStatus;
+import com.ning.billing.payment.plugin.api.PaymentMethodInfoPlugin;
 import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin.RefundPluginStatus;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.billing.util.clock.Clock;
 
-public class MockPaymentProviderPlugin extends DefaultNoOpPaymentProviderPlugin implements PaymentPluginApi {
+/**
+ * This MockPaymentProviderPlugin only works for a single accounts as we don't specify the accountId
+ * for opeartions such as addPaymentMethod.
+ */
+public class MockPaymentProviderPlugin implements NoOpPaymentPluginApi {
+
+    private static final String PLUGIN_NAME = "__NO_OP__";
+
+    private final AtomicBoolean makeNextInvoiceFailWithError = new AtomicBoolean(false);
+    private final AtomicBoolean makeNextInvoiceFailWithException = new AtomicBoolean(false);
+    private final AtomicBoolean makeAllInvoicesFailWithError = new AtomicBoolean(false);
+
+    private final Map<String, PaymentInfoPlugin> payments = new ConcurrentHashMap<String, PaymentInfoPlugin>();
+    // Note: we can't use HashMultiMap as we care about storing duplicate key/value pairs
+    private final Multimap<String, RefundInfoPlugin> refunds = LinkedListMultimap.<String, RefundInfoPlugin>create();
+    private final Map<String, PaymentMethodInfoPlugin> paymentMethods = new ConcurrentHashMap<String, PaymentMethodInfoPlugin>();
+
+    private final Clock clock;
 
     @Inject
     public MockPaymentProviderPlugin(final Clock clock) {
-        super(clock);
+        this.clock = clock;
+        clear();
+    }
+
+    @Override
+    public void clear() {
+        makeNextInvoiceFailWithException.set(false);
+        makeAllInvoicesFailWithError.set(false);
+        makeNextInvoiceFailWithError.set(false);
+    }
+
+    @Override
+    public void makeNextPaymentFailWithError() {
+        makeNextInvoiceFailWithError.set(true);
+    }
+
+    @Override
+    public void makeNextPaymentFailWithException() {
+        makeNextInvoiceFailWithException.set(true);
+    }
+
+    @Override
+    public void makeAllInvoicesFailWithError(final boolean failure) {
+        makeAllInvoicesFailWithError.set(failure);
+    }
+
+    @Override
+    public String getName() {
+        return PLUGIN_NAME;
+    }
+
+    @Override
+    public PaymentInfoPlugin processPayment(final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
+        if (makeNextInvoiceFailWithException.getAndSet(false)) {
+            throw new PaymentPluginApiException("", "test error");
+        }
+
+        final PaymentPluginStatus status = (makeAllInvoicesFailWithError.get() || makeNextInvoiceFailWithError.getAndSet(false)) ? PaymentPluginStatus.ERROR : PaymentPluginStatus.PROCESSED;
+        final PaymentInfoPlugin result = new DefaultNoOpPaymentInfoPlugin(amount, clock.getUTCNow(), clock.getUTCNow(), status, null);
+        payments.put(kbPaymentId.toString(), result);
+        return result;
+    }
+
+    @Override
+    public PaymentInfoPlugin getPaymentInfo(final UUID kbPaymentId, final TenantContext context) throws PaymentPluginApiException {
+        final PaymentInfoPlugin payment = payments.get(kbPaymentId.toString());
+        if (payment == null) {
+            throw new PaymentPluginApiException("", "No payment found for payment id " + kbPaymentId.toString());
+        }
+        return payment;
+    }
+
+
+    @Override
+    public void addPaymentMethod(final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
+        // both AccountId and externalPaymentMethodId are set to random values
+        final PaymentMethodInfoPlugin realWithID = new DefaultPaymentMethodInfoPlugin(UUID.randomUUID(), kbPaymentMethodId, setDefault, UUID.randomUUID().toString());
+        paymentMethods.put(kbPaymentMethodId.toString(), realWithID);
+    }
+
+    @Override
+    public void deletePaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
+        paymentMethods.remove(kbPaymentMethodId.toString());
+    }
+
+    @Override
+    public void setDefaultPaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
+    }
+
+    @Override
+    public List<PaymentMethodInfoPlugin> getPaymentMethods(final UUID kbAccountId, final boolean refreshFromGateway, final CallContext context) {
+        return ImmutableList.<PaymentMethodInfoPlugin>copyOf(paymentMethods.values());
+    }
+
+    @Override
+    public void resetPaymentMethods(final List<PaymentMethodInfoPlugin> input) {
+        paymentMethods.clear();
+        if (input != null) {
+            for (PaymentMethodInfoPlugin cur : input) {
+                paymentMethods.put(cur.getPaymentMethodId().toString(), cur);
+            }
+        }
+    }
+
+    @Override
+    public RefundInfoPlugin processRefund(final UUID kbPaymentId, final BigDecimal refundAmount, final CallContext context) throws PaymentPluginApiException {
+        final PaymentInfoPlugin paymentInfoPlugin = getPaymentInfo(kbPaymentId, context);
+        if (paymentInfoPlugin == null) {
+            throw new PaymentPluginApiException("", String.format("No payment found for payment id %s (plugin %s)", kbPaymentId.toString(), getName()));
+        }
+
+        BigDecimal maxAmountRefundable = paymentInfoPlugin.getAmount();
+        for (final RefundInfoPlugin refund : refunds.get(kbPaymentId.toString())) {
+            maxAmountRefundable = maxAmountRefundable.add(refund.getAmount().negate());
+        }
+        if (maxAmountRefundable.compareTo(refundAmount) < 0) {
+            throw new PaymentPluginApiException("", String.format("Refund amount of %s for payment id %s is bigger than the payment amount %s (plugin %s)",
+                                                                  refundAmount, kbPaymentId.toString(), paymentInfoPlugin.getAmount(), getName()));
+        }
+
+        final DefaultNoOpRefundInfoPlugin refundInfoPlugin = new DefaultNoOpRefundInfoPlugin(refundAmount, clock.getUTCNow(), clock.getUTCNow(), RefundPluginStatus.PROCESSED, null);
+        refunds.put(kbPaymentId.toString(), refundInfoPlugin);
+
+        return refundInfoPlugin;
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPluginProvider.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPluginProvider.java
index 3fb098d..0c4f4ac 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPluginProvider.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPluginProvider.java
@@ -19,6 +19,7 @@ package com.ning.billing.payment.provider;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
+import com.ning.billing.osgi.api.OSGIServiceDescriptor;
 import com.ning.billing.osgi.api.OSGIServiceRegistration;
 import com.ning.billing.payment.plugin.api.PaymentPluginApi;
 import com.ning.billing.util.clock.Clock;
@@ -44,7 +45,25 @@ public class MockPaymentProviderPluginProvider implements Provider<MockPaymentPr
     public MockPaymentProviderPlugin get() {
         final MockPaymentProviderPlugin plugin = new MockPaymentProviderPlugin(clock);
 
-        registry.registerService(instanceName, plugin);
+        final OSGIServiceDescriptor desc =  new OSGIServiceDescriptor() {
+            @Override
+            public String getPluginSymbolicName() {
+                return null;
+            }
+            @Override
+            public String getServiceName() {
+                return instanceName;
+            }
+            @Override
+            public String getServiceInfo() {
+                return null;
+            }
+            @Override
+            public String getServiceType() {
+                return null;
+            }
+        };
+        registry.registerService(desc, plugin);
         return plugin;
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
index f7cbd7a..281f0e9 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -59,7 +59,7 @@ public class TestRetryService extends PaymentTestSuiteNoDB {
         retryService.initialize(DefaultPaymentService.SERVICE_NAME);
         retryService.start();
 
-        mockPaymentProviderPlugin = (MockPaymentProviderPlugin) registry.getServiceForPluginName(null);
+        mockPaymentProviderPlugin = (MockPaymentProviderPlugin) registry.getServiceForName(null);
         mockPaymentProviderPlugin.clear();
     }
 

pom.xml 11(+8 -3)

diff --git a/pom.xml b/pom.xml
index 4390161..a865806 100644
--- a/pom.xml
+++ b/pom.xml
@@ -261,12 +261,12 @@
             </dependency>
             <dependency>
                 <groupId>com.ning.billing</groupId>
-                <artifactId>killbill-osgi-bundles</artifactId>
+                <artifactId>killbill-osgi-all-bundles</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
                 <groupId>com.ning.billing</groupId>
-                <artifactId>killbill-osgi-bundles-hello</artifactId>
+                <artifactId>killbill-osgi-bundles-lib-killbill</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
@@ -286,7 +286,12 @@
             </dependency>
             <dependency>
                 <groupId>com.ning.billing</groupId>
-                <artifactId>killbill-osgi-bundles-test</artifactId>
+                <artifactId>killbill-osgi-bundles-test-beatrix</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-osgi-bundles-test-payment</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestPlugin.java b/server/src/test/java/com/ning/billing/jaxrs/TestPlugin.java
index 87befef..7d4ec76 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestPlugin.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestPlugin.java
@@ -29,6 +29,7 @@ import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.ning.billing.osgi.http.DefaultServletRouter;
 import com.ning.http.client.Response;
 
 public class TestPlugin extends TestJaxrsBase {
@@ -159,7 +160,7 @@ public class TestPlugin extends TestJaxrsBase {
     }
 
     private void setupOSGIPlugin() {
-        servletRouter.registerService(TEST_PLUGIN_NAME, new HttpServlet() {
+        ((DefaultServletRouter) servletRouter).registerServiceFromPath(TEST_PLUGIN_NAME, new HttpServlet() {
             @Override
             protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
                 if (("/" + TEST_PLUGIN_VALID_GET_PATH).equals(req.getPathInfo())) {
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 3b8b7b0..9ecbad7 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
@@ -62,7 +62,6 @@ public interface OSGIConfig extends KillbillConfig {
              "com.ning.billing.usage.api," +
              "com.ning.billing.util.api," +
              "com.ning.billing.util.callcontext," +
-             "com.google.common.eventbus," +
              // javax.servlet and javax.servlet.http are not exported by default - we
              // need the bundles to see them for them to be able to register their servlets.
              // Note: bundles should mark javax.servlet:servlet-api as provided
diff --git a/util/src/test/java/com/ning/billing/payment/plugin/api/PaymentPluginApiWithTestControl.java b/util/src/test/java/com/ning/billing/payment/plugin/api/PaymentPluginApiWithTestControl.java
new file mode 100644
index 0000000..9336aab
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/payment/plugin/api/PaymentPluginApiWithTestControl.java
@@ -0,0 +1,26 @@
+/*
+ * 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.payment.plugin.api;
+
+public interface PaymentPluginApiWithTestControl extends PaymentPluginApi {
+
+    public void setPaymentPluginApiExceptionOnNextCalls(PaymentPluginApiException e);
+
+    public void setPaymentRuntimeExceptionOnNextCalls(RuntimeException e);
+
+    public void resetToNormalbehavior();
+}