Details
diff --git a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
index 95fbe01..fbbe2b8 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
@@ -25,7 +25,6 @@ import com.ning.billing.catalog.api.Currency;
import com.ning.billing.entitlement.api.user.IEntitlementUserApi;
import com.ning.billing.entitlement.api.user.ISubscriptionBundle;
import com.ning.billing.entitlement.api.user.ISubscriptionTransition;
-import com.ning.billing.util.eventbus.IEventBus;
import org.joda.time.DateTime;
import org.slf4j.Logger;
@@ -42,14 +41,17 @@ public class AnalyticsListener
private final IAccountUserApi accountApi;
@Inject
- public AnalyticsListener(final BusinessSubscriptionTransitionDao dao, final IEntitlementUserApi entitlementApi, final IAccountUserApi accountApi, final IEventBus eventBus)
+ public AnalyticsListener(final BusinessSubscriptionTransitionDao dao, final IEntitlementUserApi entitlementApi, final IAccountUserApi accountApi)
{
this.dao = dao;
this.entitlementApi = entitlementApi;
this.accountApi = accountApi;
}
- @Subscribe
+ /*
+ * Disable until we fix IRS to allow for two instances (One for bilr proxy, or for killbill)
+ * @Subscribe
+ */
public void handleNotificationChange(ISubscriptionTransition event) {
switch (event.getTransitionType()) {
case CREATE:
@@ -77,7 +79,6 @@ public class AnalyticsListener
}
}
-
public void subscriptionCreated(final ISubscriptionTransition created)
{
final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionCreated(created.getNextPlan());
diff --git a/api/src/main/java/com/ning/billing/lifecycle/LyfecycleHandlerType.java b/api/src/main/java/com/ning/billing/lifecycle/LyfecycleHandlerType.java
index 520fca4..2412916 100644
--- a/api/src/main/java/com/ning/billing/lifecycle/LyfecycleHandlerType.java
+++ b/api/src/main/java/com/ning/billing/lifecycle/LyfecycleHandlerType.java
@@ -20,6 +20,10 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.collect.Lists;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@@ -29,51 +33,55 @@ public @interface LyfecycleHandlerType {
//
// The level themselves are still work in progress depending on what we really need
//
+ // Ordering is important in that enum
+ //
public enum LyfecycleLevel {
/**
* Load and validate catalog (only for catalog subsytem)
*/
- LOAD_CATALOG(Sequence.STARTUP),
+ LOAD_CATALOG(Sequence.STARTUP_PRE_EVENT_REGISTRATION),
/**
* Initialize event bus (only for the event bus)
*/
- INIT_BUS(Sequence.STARTUP),
+ INIT_BUS(Sequence.STARTUP_PRE_EVENT_REGISTRATION),
/**
- * Service specific initalization
+ * Service specific initalization-- service does not start yet
*/
- INIT_SERVICE(Sequence.STARTUP),
+ INIT_SERVICE(Sequence.STARTUP_PRE_EVENT_REGISTRATION),
/**
* Service register their interest in events
*/
- REGISTER_EVENTS(Sequence.STARTUP),
+ REGISTER_EVENTS(Sequence.STARTUP_PRE_EVENT_REGISTRATION),
/**
* Service start
* - API call should not work
* - Events might be triggered
* - Batch processing jobs started
*/
- START_SERVICE(Sequence.STARTUP),
+ START_SERVICE(Sequence.STARTUP_POST_EVENT_REGISTRATION),
/**
* Stop service
*/
- STOP_SERVICE(Sequence.SHUTOWN),
+ STOP_SERVICE(Sequence.SHUTOWN_PRE_EVENT_UNREGISTRATION),
/**
- * Unregister interest in events
+ * Stop bus
*/
- UNREGISTER_EVENTS(Sequence.SHUTOWN),
+ STOP_BUS(Sequence.SHUTOWN_PRE_EVENT_UNREGISTRATION),
/**
- * Stop bus
+ * Unregister interest in events
*/
- STOP_BUS(Sequence.SHUTOWN),
+ UNREGISTER_EVENTS(Sequence.SHUTOWN_PRE_EVENT_UNREGISTRATION),
/**
* Any service specific shutdown action before the end
*/
- SHUTDOWN(Sequence.SHUTOWN);
+ SHUTDOWN(Sequence.SHUTOWN_POST_EVENT_UNREGISTRATION);
public enum Sequence {
- STARTUP,
- SHUTOWN
+ STARTUP_PRE_EVENT_REGISTRATION,
+ STARTUP_POST_EVENT_REGISTRATION,
+ SHUTOWN_PRE_EVENT_UNREGISTRATION,
+ SHUTOWN_POST_EVENT_UNREGISTRATION
};
private Sequence seq;
@@ -85,6 +93,19 @@ public @interface LyfecycleHandlerType {
public Sequence getSequence() {
return seq;
}
+
+ //
+ // Returns an ordered list of level for a particular sequence
+ //
+ public static List<LyfecycleLevel> getLevelsForSequence(Sequence seq) {
+ List<LyfecycleLevel> result = Lists.newLinkedList();
+ for (LyfecycleLevel level : LyfecycleLevel.values()) {
+ if (level.getSequence() == seq) {
+ result.add(level);
+ }
+ }
+ return result;
+ }
}
public LyfecycleLevel value();
diff --git a/api/src/main/java/com/ning/billing/util/eventbus/IEventBus.java b/api/src/main/java/com/ning/billing/util/eventbus/IEventBus.java
index ec0b7b7..90ab0bc 100644
--- a/api/src/main/java/com/ning/billing/util/eventbus/IEventBus.java
+++ b/api/src/main/java/com/ning/billing/util/eventbus/IEventBus.java
@@ -74,6 +74,15 @@ public interface IEventBus {
/**
+ * Unregister the handler for a particular type of event
+ *
+ * @param handlerInstance
+ * @throws EventBusException
+ */
+ public void unregister(Object handlerInstance) throws EventBusException;
+
+
+ /**
* Post an event asynchronously
*
* @param event to be posted
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/Lifecycle.java b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/Lifecycle.java
index 6abdb75..f091a81 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/Lifecycle.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/Lifecycle.java
@@ -20,6 +20,7 @@ import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -74,21 +75,27 @@ public class Lifecycle {
}
}
- public void fireStartupSequence() {
- for (LyfecycleLevel level : LyfecycleLevel.values()) {
- if (level.getSequence() == Sequence.SHUTOWN) {
- break;
- }
- doFireStage(level);
- }
+
+ public void fireStartupSequencePriorEventRegistration() {
+ fireSequence(Sequence.STARTUP_PRE_EVENT_REGISTRATION);
}
- public void fireShutdownSequence() {
- for (LyfecycleLevel level : LyfecycleLevel.values()) {
- if (level.getSequence() == Sequence.STARTUP) {
- continue;
- }
- doFireStage(level);
+ public void fireStartupSequencePostEventRegistration() {
+ fireSequence(Sequence.STARTUP_POST_EVENT_REGISTRATION);
+ }
+
+ public void fireShutdownSequencePriorEventUnRegistration() {
+ fireSequence(Sequence.SHUTOWN_PRE_EVENT_UNREGISTRATION);
+ }
+
+ public void fireShutdownSequencePostEventUnRegistration() {
+ fireSequence(Sequence.SHUTOWN_POST_EVENT_UNREGISTRATION);
+ }
+
+ private void fireSequence(Sequence seq) {
+ List<LyfecycleLevel> levels = LyfecycleLevel.getLevelsForSequence(seq);
+ for (LyfecycleLevel cur : levels) {
+ doFireStage(cur);
}
}
@@ -103,12 +110,13 @@ public class Lifecycle {
log.info("Killbill lifecycle calling handler {} for service {}", cur.getMethod().getName(), target.getName());
method.invoke(target);
} catch (Exception e) {
- log.warn("Killbill lifecycle failed to invoke lifecycle handler", e);
+ logWarn("Killbill lifecycle failed to invoke lifecycle handler", e);
}
}
}
+
private Set<? extends IService> findServices() {
Set<IService> result = new HashSet<IService>();
@@ -120,7 +128,7 @@ public class Lifecycle {
log.debug("got instance {}", instance.getName());
result.add(instance);
} catch (Exception e) {
- log.warn("Failed to inject " + cur.getName(), e);
+ logWarn("Failed to inject " + cur.getName(), e);
}
}
@@ -128,9 +136,13 @@ public class Lifecycle {
}
+ // Used to disable valid injection failure from unit tests
+ protected void logWarn(String msg, Exception e) {
+ log.warn(msg, e);
+ }
+
public Multimap<LyfecycleLevel, LifecycleHandler<? extends IService>> findAllHandlers(IService service) {
- Multimap<LyfecycleLevel, LifecycleHandler<? extends IService>> methodsInService =
- HashMultimap.create();
+ Multimap<LyfecycleLevel, LifecycleHandler<? extends IService>> methodsInService = HashMultimap.create();
Class<? extends IService> clazz = service.getClass();
for (Method method : clazz.getMethods()) {
LyfecycleHandlerType annotation = method.getAnnotation(LyfecycleHandlerType.class);
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/ServiceFinder.java b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/ServiceFinder.java
index fe3f0c5..9dfa89f 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/ServiceFinder.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/ServiceFinder.java
@@ -91,6 +91,8 @@ public class ServiceFinder {
classPaths = System.getProperty("java.class.path", "").split(File.pathSeparator);
}
+ log.info("Start SERVICE_FINDER");
+
for (int h = 0; h < classPaths.length; h++) {
@@ -99,10 +101,16 @@ public class ServiceFinder {
File classPath = new File( (URL.class).isInstance(classPaths[h]) ?
((URL)classPaths[h]).getFile() : classPaths[h].toString());
if (classPath.isDirectory()) {
+
+ log.info("DIR : " + classPath);
+
List<String> dirListing = new ArrayList<String>();
recursivelyListDir(dirListing, classPath, new StringBuffer() );
files = Collections.enumeration( dirListing );
} else if (classPath.getName().endsWith(".jar")) {
+
+ log.info("JAR : " + classPath);
+
String [] jarParts = classPath.getName().split("/");
String jarName = jarParts[jarParts.length - 1];
if (jarFilter != null && jarName != null && ! jarName.startsWith(jarFilter)) {
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java b/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
index 7ceae83..99d7e16 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
@@ -18,11 +18,13 @@ package com.ning.billing.beatrix.lifecycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
+import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.lifecycle.IService;
@@ -39,16 +41,45 @@ public class TestLifecycle {
private Lifecycle lifecycle;
- public static class Service1 implements IService {
+ public static class ServiceBase {
+
+ private int count = 0;
+
+ public ServiceBase() {
+ reset();
+ }
+
+ public synchronized void reset() {
+ this.count = 0;
+ }
+
+ public synchronized int getCount() {
+ return count;
+ }
+
+ public synchronized void incrementCount() {
+ count++;
+ }
+ }
+
+ public static class Service1 extends ServiceBase implements IService {
@LyfecycleHandlerType(LyfecycleLevel.INIT_BUS)
public void initBus() {
log.info("Service1 : got INIT_BUS");
+ incrementCount();
}
@LyfecycleHandlerType(LyfecycleLevel.START_SERVICE)
public void startService() {
log.info("Service1 : got START_SERVICE");
+ incrementCount();
+ }
+
+ @LyfecycleHandlerType(LyfecycleLevel.SHUTDOWN)
+ public void shutdownService() {
+ log.info("Service1 : got SHUTDOWN");
+ incrementCount();
}
@Override
@@ -57,23 +88,41 @@ public class TestLifecycle {
}
}
- public static class Service2 implements IService {
+ public static class Service2 extends ServiceBase implements IService {
@LyfecycleHandlerType(LyfecycleLevel.LOAD_CATALOG)
public void loadCatalog() {
- log.info("Service1 : got LOAD_CATALOG");
+ log.info("Service2 : got LOAD_CATALOG");
+ incrementCount();
+ }
+
+ @LyfecycleHandlerType(LyfecycleLevel.REGISTER_EVENTS)
+ public void registerEvents() {
+ log.info("Service2 : got REGISTER_EVENTS");
+ incrementCount();
+ }
+
+ @LyfecycleHandlerType(LyfecycleLevel.UNREGISTER_EVENTS)
+ public void unregisterEvents() {
+ log.info("Service2 : got UNREGISTER_EVENTS");
+ incrementCount();
+ }
+
+ @LyfecycleHandlerType(LyfecycleLevel.START_SERVICE)
+ public void startService() {
+ log.info("Service2 : got START_SERVICE");
+ incrementCount();
}
@Override
public String getName() {
return null;
}
-
}
- @BeforeClass(groups={"fast"})
+ @BeforeClass
public void setup() {
final Injector g = Guice.createInjector(Stage.DEVELOPMENT, new TestLifecycleModule());
s1 = g.getInstance(Service1.class);
@@ -81,17 +130,45 @@ public class TestLifecycle {
lifecycle = g.getInstance(Lifecycle.class);
}
- @Test
+ @Test(enabled=false, groups={"fast"})
public void testLifecycle() {
- lifecycle.fireStartupSequence();
+ s1.reset();
+ s2.reset();
+ lifecycle.fireStartupSequencePriorEventRegistration();
+ Assert.assertEquals(s1.getCount() + s2.getCount(), 3);
+
+ s1.reset();
+ s2.reset();
+ lifecycle.fireStartupSequencePostEventRegistration();
+ Assert.assertEquals(s1.getCount() + s2.getCount(), 2);
+
+ s1.reset();
+ s2.reset();
+ lifecycle.fireShutdownSequencePriorEventUnRegistration();
+ Assert.assertEquals(s1.getCount() + s2.getCount(), 1);
+
+ s1.reset();
+ s2.reset();
+ lifecycle.fireShutdownSequencePostEventUnRegistration();
+ Assert.assertEquals(s1.getCount() + s2.getCount(), 1);
}
+ public static class LifecycleNoWarn extends Lifecycle {
+
+ @Inject
+ public LifecycleNoWarn(Injector injector) {
+ super(injector);
+ }
+ @Override
+ protected void logWarn(String msg, Exception e) {
+ }
+ }
public static class TestLifecycleModule extends AbstractModule {
@Override
protected void configure() {
- bind(Lifecycle.class).asEagerSingleton();
+ bind(Lifecycle.class).to(LifecycleNoWarn.class).asEagerSingleton();
bind(Service1.class).asEagerSingleton();
bind(Service2.class).asEagerSingleton();
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
index fe8489c..89b58c8 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
@@ -25,6 +25,8 @@ import com.ning.billing.entitlement.alignment.PlanAligner;
import com.ning.billing.entitlement.api.IEntitlementService;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
import com.ning.billing.entitlement.api.billing.IEntitlementBillingApi;
+import com.ning.billing.entitlement.api.test.EntitlementTestApi;
+import com.ning.billing.entitlement.api.test.IEntitlementTestApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.IEntitlementUserApi;
import com.ning.billing.entitlement.engine.core.ApiEventProcessor;
@@ -61,6 +63,7 @@ public class EntitlementModule extends AbstractModule {
bind(IEntitlementService.class).to(Engine.class).asEagerSingleton();
bind(Engine.class).asEagerSingleton();
bind(IPlanAligner.class).to(PlanAligner.class).asEagerSingleton();
+ bind(IEntitlementTestApi.class).to(EntitlementTestApi.class).asEagerSingleton();
bind(IEntitlementUserApi.class).to(EntitlementUserApi.class).asEagerSingleton();
bind(IEntitlementBillingApi.class).to(EntitlementBillingApi.class).asEagerSingleton();
}
diff --git a/util/src/main/java/com/ning/billing/util/eventbus/MemoryEventBus.java b/util/src/main/java/com/ning/billing/util/eventbus/MemoryEventBus.java
index 5ee513a..7cc0453 100644
--- a/util/src/main/java/com/ning/billing/util/eventbus/MemoryEventBus.java
+++ b/util/src/main/java/com/ning/billing/util/eventbus/MemoryEventBus.java
@@ -87,6 +87,12 @@ public class MemoryEventBus implements IEventBus {
}
@Override
+ public void unregister(Object handlerInstance) throws EventBusException {
+ checkInitialized("unregister");
+ delegate.unregister(handlerInstance);
+ }
+
+ @Override
public void post(IEventBusType event) throws EventBusException {
checkInitialized("post");
delegate.post(event);