killbill-uncached

Fix jruby base osgi plugin to support both Notification and

5/9/2013 3:27:03 PM

Details

diff --git a/api/src/main/java/com/ning/billing/notification/plugin/api/NotificationPluginApi.java b/api/src/main/java/com/ning/billing/notification/plugin/api/NotificationPluginApi.java
new file mode 100644
index 0000000..4dc0fdb
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/notification/plugin/api/NotificationPluginApi.java
@@ -0,0 +1,29 @@
+/*
+ * 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.notification.plugin.api;
+
+import com.ning.billing.beatrix.bus.api.ExtBusEvent;
+
+public interface NotificationPluginApi {
+
+    /**
+     * Dispatching of external Killbill events for notification plugins
+     *
+     * @param killbillEvent the killbill event
+     */
+    public void onEvent(ExtBusEvent killbillEvent);
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestJrubyNotificationPlugin.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestJrubyNotificationPlugin.java
new file mode 100644
index 0000000..e817a63
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestJrubyNotificationPlugin.java
@@ -0,0 +1,33 @@
+package com.ning.billing.beatrix.integration.osgi;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.beatrix.osgi.SetupBundleWithAssertion;
+
+public class TestJrubyNotificationPlugin extends TestOSGIBase {
+
+    private final String BUNDLE_TEST_RESOURCE_PREFIX = "killbill-notification-test";
+    private final String BUNDLE_TEST_RESOURCE = BUNDLE_TEST_RESOURCE_PREFIX + ".tar.gz";
+
+    @BeforeClass(groups = "slow", enabled = true)
+    public void beforeClass() throws Exception {
+
+        // OSGIDataSourceConfig
+        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.setupJrubyBundle();
+    }
+
+    @Test(groups = "slow", enabled = true)
+    public void testOnEventForAccountCreation() throws Exception {
+
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(4));
+    }
+
+}
diff --git a/beatrix/src/test/resources/killbill-notification-test.tar.gz b/beatrix/src/test/resources/killbill-notification-test.tar.gz
new file mode 100644
index 0000000..9e9e3ea
Binary files /dev/null and b/beatrix/src/test/resources/killbill-notification-test.tar.gz differ
diff --git a/beatrix/src/test/resources/killbill-payment-test.tar.gz b/beatrix/src/test/resources/killbill-payment-test.tar.gz
index 6561b10..1d84c69 100644
Binary files a/beatrix/src/test/resources/killbill-payment-test.tar.gz and b/beatrix/src/test/resources/killbill-payment-test.tar.gz differ
diff --git a/osgi-bundles/bundles/jruby/pom.xml b/osgi-bundles/bundles/jruby/pom.xml
index 8e19afc..dcf2aaf 100644
--- a/osgi-bundles/bundles/jruby/pom.xml
+++ b/osgi-bundles/bundles/jruby/pom.xml
@@ -49,6 +49,12 @@
             <version>1.7.1</version>
         </dependency>
         <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>14.0.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
         </dependency>
diff --git a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyActivator.java b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyActivator.java
index e70c2cc..0e5cd9a 100644
--- a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyActivator.java
+++ b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyActivator.java
@@ -38,6 +38,9 @@ public class JRubyActivator extends KillbillActivatorBase {
 
     private JRubyPlugin plugin = null;
 
+    private final static String KILLBILL_PLUGIN_JPAYMENT = "Killbill::Plugin::JPayment";
+    private final static String KILLBILL_PLUGIN_JNOTIFICATION = "Killbill::Plugin::JNotification";
+
     public void start(final BundleContext context) throws Exception {
 
         super.start(context);
@@ -52,12 +55,17 @@ public class JRubyActivator extends KillbillActivatorBase {
                 final PluginRubyConfig rubyConfig = retrievePluginRubyConfig(context);
 
                 // Setup JRuby
+                final String pluginMain;
                 final ScriptingContainer scriptingContainer = setupScriptingContainer(rubyConfig);
                 if (PluginType.NOTIFICATION.equals(rubyConfig.getPluginType())) {
                     plugin = new JRubyNotificationPlugin(rubyConfig, scriptingContainer, context, logService);
                     dispatcher.registerEventHandler((OSGIKillbillEventHandler) plugin);
+                    pluginMain = KILLBILL_PLUGIN_JNOTIFICATION;
                 } else if (PluginType.PAYMENT.equals(rubyConfig.getPluginType())) {
                     plugin = new JRubyPaymentPlugin(rubyConfig, scriptingContainer, context, logService);
+                    pluginMain = KILLBILL_PLUGIN_JPAYMENT;
+                } else {
+                    throw new IllegalStateException("Unsupported plugin type " + rubyConfig.getPluginType());
                 }
 
                 // Validate and instantiate the plugin
@@ -67,7 +75,7 @@ public class JRubyActivator extends KillbillActivatorBase {
                 killbillServices.put("logger", logService);
                 // Default to the plugin root dir if no jruby plugins specific configuration directory was specified
                 killbillServices.put("conf_dir", Objects.firstNonNull(jrubyPluginsConfDir, rubyConfig.getPluginVersionRoot().getAbsolutePath()));
-                plugin.instantiatePlugin(killbillServices);
+                plugin.instantiatePlugin(killbillServices, pluginMain);
 
                 logService.log(LogService.LOG_INFO, "Starting JRuby plugin " + plugin.getPluginMainClass());
                 plugin.startPlugin(context);
diff --git a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyNotificationPlugin.java b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyNotificationPlugin.java
index 2e49ec5..fa6118f 100644
--- a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyNotificationPlugin.java
+++ b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyNotificationPlugin.java
@@ -16,13 +16,17 @@
 
 package com.ning.billing.osgi.bundles.jruby;
 
+import org.jruby.Ruby;
 import org.jruby.embed.ScriptingContainer;
 import org.jruby.javasupport.JavaEmbedUtils;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.log.LogService;
 
 import com.ning.billing.beatrix.bus.api.ExtBusEvent;
+import com.ning.billing.notification.plugin.api.NotificationPluginApi;
 import com.ning.billing.osgi.api.config.PluginRubyConfig;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
 import com.ning.killbill.osgi.libs.killbill.OSGIKillbillEventDispatcher.OSGIKillbillEventHandler;
 
 public class JRubyNotificationPlugin extends JRubyPlugin implements OSGIKillbillEventHandler {
@@ -39,8 +43,17 @@ public class JRubyNotificationPlugin extends JRubyPlugin implements OSGIKillbill
 
     @Override
     public void handleKillbillEvent(final ExtBusEvent killbillEvent) {
-        checkValidNotificationPlugin();
-        checkPluginIsRunning();
-        pluginInstance.callMethod("on_event", JavaEmbedUtils.javaToRuby(getRuntime(), killbillEvent));
+
+        try {
+            callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.NOTIFICATION) {
+                @Override
+                public Void doCall(final Ruby runtime) throws PaymentPluginApiException {
+                    ((NotificationPluginApi) pluginInstance).onEvent(killbillEvent);
+                    return null;
+                }
+            });
+        } catch (PaymentPluginApiException e) {
+            throw new IllegalStateException("Unexpected PaymentApiException for notification plugin");
+        }
     }
 }
diff --git a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
index 99ab86b..3b52ee3 100644
--- a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
+++ b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
@@ -24,8 +24,6 @@ import java.util.UUID;
 
 import org.jruby.Ruby;
 import org.jruby.embed.ScriptingContainer;
-import org.jruby.javasupport.JavaEmbedUtils;
-import org.jruby.runtime.builtin.IRubyObject;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.log.LogService;
@@ -70,9 +68,9 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
 
 
     @Override
-    public PaymentInfoPlugin processPayment(final UUID kbAccountId, final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final Currency currency,  final CallContext context) throws PaymentPluginApiException {
+    public PaymentInfoPlugin processPayment(final UUID kbAccountId, final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final Currency currency, final CallContext context) throws PaymentPluginApiException {
 
-        return callWithRuntimeAndChecking(new PluginCallback() {
+        return callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
             public PaymentInfoPlugin doCall(final Ruby runtime) throws PaymentPluginApiException {
                 return ((PaymentPluginApi) pluginInstance).processPayment(kbAccountId, kbPaymentId, kbPaymentMethodId, amount, currency, context);
@@ -83,7 +81,7 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
     @Override
     public PaymentInfoPlugin getPaymentInfo(final UUID kbAccountId, final UUID kbPaymentId, final TenantContext context) throws PaymentPluginApiException {
 
-        return callWithRuntimeAndChecking(new PluginCallback()  {
+        return callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
             public PaymentInfoPlugin doCall(final Ruby runtime) throws PaymentPluginApiException {
                 return ((PaymentPluginApi) pluginInstance).getPaymentInfo(kbAccountId, kbPaymentId, context);
@@ -94,7 +92,7 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
     @Override
     public RefundInfoPlugin processRefund(final UUID kbAccountId, final UUID kbPaymentId, final BigDecimal refundAmount, final Currency currency, final CallContext context) throws PaymentPluginApiException {
 
-        return callWithRuntimeAndChecking(new PluginCallback()  {
+        return callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
             public RefundInfoPlugin doCall(final Ruby runtime) throws PaymentPluginApiException {
                 return ((PaymentPluginApi) pluginInstance).processRefund(kbAccountId, kbPaymentId, refundAmount, currency, context);
@@ -105,7 +103,7 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
 
     @Override
     public List<RefundInfoPlugin> getRefundInfo(final UUID kbAccountId, final UUID kbPaymentId, final TenantContext context) throws PaymentPluginApiException {
-        return callWithRuntimeAndChecking(new PluginCallback()  {
+        return callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
             public List<RefundInfoPlugin> doCall(final Ruby runtime) throws PaymentPluginApiException {
                 return ((PaymentPluginApi) pluginInstance).getRefundInfo(kbAccountId, kbPaymentId, context);
@@ -116,9 +114,9 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
     @Override
     public void addPaymentMethod(final UUID kbAccountId, final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
 
-        callWithRuntimeAndChecking(new PluginCallback() {
+        callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
-            public Void doCall(final Ruby runtime) throws PaymentPluginApiException  {
+            public Void doCall(final Ruby runtime) throws PaymentPluginApiException {
                 ((PaymentPluginApi) pluginInstance).addPaymentMethod(kbAccountId, kbPaymentMethodId, paymentMethodProps, Boolean.valueOf(setDefault), context);
                 return null;
             }
@@ -128,9 +126,9 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
     @Override
     public void deletePaymentMethod(final UUID kbAccountId, final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
 
-        callWithRuntimeAndChecking(new PluginCallback() {
+        callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
-            public Void doCall(final Ruby runtime) throws PaymentPluginApiException  {
+            public Void doCall(final Ruby runtime) throws PaymentPluginApiException {
                 ((PaymentPluginApi) pluginInstance).deletePaymentMethod(kbAccountId, kbPaymentMethodId, context);
                 return null;
             }
@@ -140,7 +138,7 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
     @Override
     public PaymentMethodPlugin getPaymentMethodDetail(final UUID kbAccountId, final UUID kbPaymentMethodId, final TenantContext context) throws PaymentPluginApiException {
 
-        return callWithRuntimeAndChecking(new PluginCallback()  {
+        return callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
             public PaymentMethodPlugin doCall(final Ruby runtime) throws PaymentPluginApiException {
                 return ((PaymentPluginApi) pluginInstance).getPaymentMethodDetail(kbAccountId, kbPaymentMethodId, context);
@@ -151,7 +149,7 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
     @Override
     public void setDefaultPaymentMethod(final UUID kbAccountId, final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
 
-        callWithRuntimeAndChecking(new PluginCallback()  {
+        callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
             public Void doCall(final Ruby runtime) throws PaymentPluginApiException {
                 ((PaymentPluginApi) pluginInstance).setDefaultPaymentMethod(kbAccountId, kbPaymentMethodId, context);
@@ -162,7 +160,7 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
 
     @Override
     public List<PaymentMethodInfoPlugin> getPaymentMethods(final UUID kbAccountId, final boolean refreshFromGateway, final CallContext context) throws PaymentPluginApiException {
-        return callWithRuntimeAndChecking(new PluginCallback() {
+        return callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
             public List<PaymentMethodInfoPlugin> doCall(final Ruby runtime) throws PaymentPluginApiException {
                 return ((PaymentPluginApi) pluginInstance).getPaymentMethods(kbAccountId, Boolean.valueOf(refreshFromGateway), context);
@@ -173,38 +171,14 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
     @Override
     public void resetPaymentMethods(final UUID kbAccountId, final List<PaymentMethodInfoPlugin> paymentMethods) throws PaymentPluginApiException {
 
-        callWithRuntimeAndChecking(new PluginCallback() {
+        callWithRuntimeAndChecking(new PluginCallback(VALIDATION_PLUGIN_TYPE.PAYMENT) {
             @Override
-            public Void doCall(final Ruby runtime) throws PaymentPluginApiException  {
+            public Void doCall(final Ruby runtime) throws PaymentPluginApiException {
                 ((PaymentPluginApi) pluginInstance).resetPaymentMethods(kbAccountId, paymentMethods);
                 return null;
             }
         });
     }
 
-    private abstract class PluginCallback {
-
-        public abstract <T> T doCall(final Ruby runtime) throws PaymentPluginApiException;
-
-        public boolean checkValidPaymentPlugin() {
-            return true;
-        }
-    }
 
-    private <T> T callWithRuntimeAndChecking(PluginCallback cb) throws PaymentPluginApiException {
-        try {
-            checkPluginIsRunning();
-
-            if (cb.checkValidPaymentPlugin()) {
-                checkValidPaymentPlugin();
-            }
-
-            final Ruby runtime = getRuntime();
-            return cb.doCall(runtime);
-
-        } catch (RuntimeException e) {
-            // TODO STEPH not sure what ruby can throw
-            throw e;
-        }
-    }
 }
diff --git a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPlugin.java b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPlugin.java
index d45ee1a..9f4f391 100644
--- a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPlugin.java
+++ b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPlugin.java
@@ -30,12 +30,17 @@ import org.jruby.runtime.builtin.IRubyObject;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.log.LogService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.ning.billing.osgi.api.config.PluginRubyConfig;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
 
 // Bridge between the OSGI bundle and the ruby plugin
 public abstract class JRubyPlugin {
 
+    private final static Logger log = LoggerFactory.getLogger(JRubyPlugin.class);
+
     // Killbill gem base classes
     private static final String KILLBILL_PLUGIN_BASE = "Killbill::Plugin::PluginBase";
     private static final String KILLBILL_PLUGIN_NOTIFICATION = "Killbill::Plugin::Notification";
@@ -82,7 +87,7 @@ public abstract class JRubyPlugin {
         return pluginLibdir;
     }
 
-    public void instantiatePlugin(final Map<String, Object> killbillApis) {
+    public void instantiatePlugin(final Map<String, Object> killbillApis, final String pluginMain) {
         checkValidPlugin();
 
         // Register all killbill APIs
@@ -93,7 +98,7 @@ public abstract class JRubyPlugin {
         // Don't put any code here!
 
         // Start the plugin
-        pluginInstance = (RubyObject) container.runScriptlet("Killbill::Plugin::JPayment.new(" + KILLBILL_PLUGIN_CLASS_NAME + "," + KILLBILL_SERVICES + ")");
+        pluginInstance = (RubyObject) container.runScriptlet(pluginMain + ".new(" + KILLBILL_PLUGIN_CLASS_NAME + "," + KILLBILL_SERVICES + ")");
     }
 
     public void startPlugin(final BundleContext context) {
@@ -130,7 +135,7 @@ public abstract class JRubyPlugin {
     }
 
     protected void checkPluginIsRunning() {
-        if (pluginInstance == null || ! (Boolean) pluginInstance.callMethod("is_active").toJava(Boolean.class)) {
+        if (pluginInstance == null || !(Boolean) pluginInstance.callMethod("is_active").toJava(Boolean.class)) {
             throw new IllegalStateException(String.format("Plugin %s didn't start properly", pluginMainClass));
         }
     }
@@ -194,10 +199,10 @@ public abstract class JRubyPlugin {
                    .append("end\n");
             builder.append("begin\n")
                    .append("require '").append(pluginGemName).append("'\n")
-                   .append("rescue LoadError\n")
-                   // Could be useful for debugging
-                   //.append("warn \"WARN: unable to require ").append(pluginGemName).append("\"\n")
-                   .append("end\n");
+                    .append("rescue LoadError\n")
+                            // Could be useful for debugging
+                            //.append("warn \"WARN: unable to require ").append(pluginGemName).append("\"\n")
+                    .append("end\n");
             // Load the extra require file, if specified
             if (rubyRequire != null) {
                 builder.append("begin\n")
@@ -218,4 +223,48 @@ public abstract class JRubyPlugin {
     protected Ruby getRuntime() {
         return pluginInstance.getMetaClass().getRuntime();
     }
+
+    public enum VALIDATION_PLUGIN_TYPE {
+        NOTIFICATION,
+        PAYMENT,
+        NONE
+    }
+
+    protected abstract class PluginCallback {
+
+        private final VALIDATION_PLUGIN_TYPE pluginType;
+
+        public PluginCallback(final VALIDATION_PLUGIN_TYPE pluginType) {
+            this.pluginType = pluginType;
+        }
+
+        public abstract <T> T doCall(final Ruby runtime) throws PaymentPluginApiException;
+
+        public VALIDATION_PLUGIN_TYPE getPluginType() {
+            return pluginType;
+        }
+    }
+
+    protected <T> T callWithRuntimeAndChecking(final PluginCallback cb) throws PaymentPluginApiException {
+        try {
+            checkPluginIsRunning();
+
+            switch(cb.getPluginType()) {
+                case NOTIFICATION:
+                    checkValidNotificationPlugin();
+                    break;
+                case PAYMENT:
+                    checkValidPaymentPlugin();
+                    break;
+                default:
+                    break;
+            }
+
+            final Ruby runtime = getRuntime();
+            return cb.doCall(runtime);
+        } catch (RuntimeException e) {
+            log.warn("RuntimeException in jruby plugin ", e);
+            throw e;
+        }
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/mock/api/MockExtBusEvent.java b/util/src/test/java/com/ning/billing/mock/api/MockExtBusEvent.java
new file mode 100644
index 0000000..688c90a
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/api/MockExtBusEvent.java
@@ -0,0 +1,66 @@
+package com.ning.billing.mock.api;
+
+import java.util.UUID;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.beatrix.bus.api.ExtBusEvent;
+import com.ning.billing.beatrix.bus.api.ExtBusEventType;
+
+/**
+ * Used for Jruby plugin that import util test package for default implementation of interfaces in api.
+ * So despite the appearences, this class is used.
+ */
+public class MockExtBusEvent implements ExtBusEvent {
+
+    private final ExtBusEventType eventType;
+    private final ObjectType objectType;
+    private final UUID objectId;
+    private final UUID accountId;
+    private final UUID tenantId;
+
+
+    public MockExtBusEvent(final ExtBusEventType eventType,
+                           final ObjectType objectType,
+                           final UUID objectId,
+                           final UUID accountId,
+                           final UUID tenantId) {
+        this.eventType = eventType;
+        this.objectId = objectId;
+        this.objectType = objectType;
+        this.accountId = accountId;
+        this.tenantId = tenantId;
+    }
+
+    @Override
+    public ExtBusEventType getEventType() {
+        return eventType;
+    }
+
+    @Override
+    public ObjectType getObjectType() {
+        return objectType;
+    }
+
+    @Override
+    public UUID getObjectId() {
+        return objectId;
+    }
+
+    @Override
+    public UUID getAccountId() {
+        return accountId;
+    }
+
+    @Override
+    public UUID getTenantId() {
+        return tenantId;
+    }
+
+    @Override
+    public String toString() {
+        return "MockExtBusEvent [eventType=" + eventType + ", objectType="
+               + objectType + ", objectId=" + objectId + ", accountId="
+               + accountId + ", tenantId=" + tenantId + "]";
+    }
+
+}
diff --git a/util/src/test/java/com/ning/billing/util/clock/TestClockMock.java b/util/src/test/java/com/ning/billing/util/clock/TestClockMock.java
index ad5e9db..b080f69 100644
--- a/util/src/test/java/com/ning/billing/util/clock/TestClockMock.java
+++ b/util/src/test/java/com/ning/billing/util/clock/TestClockMock.java
@@ -38,7 +38,7 @@ public class TestClockMock extends UtilTestSuiteNoDB {
 
         final DateTime startingTime = new DateTime(DateTimeZone.UTC);
         // Lame, but required due to the truncation magic
-        Awaitility.await().atMost(999, MILLISECONDS).until(new Callable<Boolean>() {
+        Awaitility.await().atMost(1001, MILLISECONDS).until(new Callable<Boolean>() {
             @Override
             public Boolean call() throws Exception {
                 return clock.getUTCNow().isAfter(startingTime);