killbill-memoizeit

Large merge with Integration code from Stephane, plus a refactor

4/16/2012 9:02:43 PM

Changes

analytics/pom.xml 11(+11 -0)

bin/db-helper 149(+74 -75)

bin/start-server 99(+99 -0)

catalog/src/test/java/com/ning/billing/catalog/overdue/TestBundleCondition.java 76(+0 -76)

doc/api.html 91(+91 -0)

doc/css/prettify.css 118(+118 -0)

doc/design.html 100(+100 -0)

doc/js/prettify.js 28(+28 -0)

doc/setup.html 97(+97 -0)

doc/user.html 102(+102 -0)

entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java 197(+0 -197)

index.html 120(+120 -0)

jaxrs/pom.xml 97(+97 -0)

ne/pom.xml 120(+120 -0)

overdue/pom.xml 6(+5 -1)

overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java 74(+0 -74)

overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg 15(+0 -15)

payment/src/main/java/com/ning/billing/payment/util/EventBusFuture.java 75(+0 -75)

payment/src/test/java/com/ning/billing/payment/util/TestSyncWaitOnEventBus.java 102(+0 -102)

pom.xml 69(+58 -11)

server/pom.xml 426(+426 -0)

Details

diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
index 7b5ed63..efeb07d 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
@@ -49,6 +49,7 @@ public class DefaultAccount extends ExtendedEntityBase implements Account {
 	private final String phone;
     private final String updatedBy;
     private final DateTime updatedDate;
+    
 
 	//intended for creation and migration
 	public DefaultAccount(final String createdBy, final DateTime createdDate,
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeNotification.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeNotification.java
index 11a5a39..85401d7 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeNotification.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeNotification.java
@@ -17,7 +17,7 @@
 package com.ning.billing.account.api.user;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountChangeNotification;
+import com.ning.billing.account.api.AccountChangeEvent;
 import com.ning.billing.account.api.ChangedField;
 import com.ning.billing.account.api.DefaultChangedField;
 
@@ -25,15 +25,29 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
-public class DefaultAccountChangeNotification implements AccountChangeNotification {
+public class DefaultAccountChangeNotification implements AccountChangeEvent {
+	
+	private final UUID userToken;
     private final List<ChangedField> changedFields;
     private final UUID id;
 
-    public DefaultAccountChangeNotification(UUID id, Account oldData, Account newData) {
+    public DefaultAccountChangeNotification(UUID id, UUID userToken, Account oldData, Account newData) {
         this.id = id;
+        this.userToken = userToken;
         this.changedFields = calculateChangedFields(oldData, newData);
     }
 
+    
+	@Override
+	public BusEventType getBusEventType() {
+		return BusEventType.ACCOUNT_CHANGE;
+	}
+
+	   @Override
+	    public UUID getUserToken() {
+	    	return userToken;
+	    }
+
     @Override
     public UUID getAccountId() {
         return id;
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
index 91d9b82..9e5a9f1 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
@@ -17,20 +17,33 @@
 package com.ning.billing.account.api.user;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountCreationNotification;
+import com.ning.billing.account.api.AccountCreationEvent;
 import com.ning.billing.account.api.AccountData;
+import com.ning.billing.util.bus.BusEvent.BusEventType;
 
 import java.util.UUID;
 
-public class DefaultAccountCreationEvent implements AccountCreationNotification {
+public class DefaultAccountCreationEvent implements AccountCreationEvent {
+	
+	private final UUID userToken;	
     private final UUID id;
     private final AccountData data;
 
-    public DefaultAccountCreationEvent(Account data) {
+    public DefaultAccountCreationEvent(Account data, UUID userToken) {
         this.id = data.getId();
         this.data = data;
+        this.userToken = userToken;
     }
 
+	@Override
+	public BusEventType getBusEventType() {
+		return BusEventType.ACCOUNT_CREATE;
+	}
+
+    @Override
+    public UUID getUserToken() {
+    	return userToken;
+    }
     @Override
     public UUID getId() {
         return id;
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
index eb49bf5..6f8d856 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
@@ -98,7 +98,7 @@ public class DefaultAccountUserApi implements com.ning.billing.account.api.Accou
         try {
             dao.update(account, context);
         } catch (EntityPersistenceException e) {
-            throw new AccountApiException(e, ErrorCode.ACCOUNT_UPDATE_FAILED);
+            throw new AccountApiException(e, e.getCode(), e.getMessage());
         }
   
     }
@@ -106,10 +106,9 @@ public class DefaultAccountUserApi implements com.ning.billing.account.api.Accou
     @Override
     public void updateAccount(final String externalKey, final AccountData accountData, final CallContext context) throws AccountApiException {
     	UUID accountId = getIdFromKey(externalKey);
-    	if(accountId == null) {
+    	if (accountId == null) {
     		throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, externalKey);
     	}
-
     	updateAccount(accountId, accountData, context);
      }
 
diff --git a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
index 2d06666..b9a2b31 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
@@ -33,8 +33,8 @@ import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
-import com.ning.billing.account.api.AccountChangeNotification;
-import com.ning.billing.account.api.AccountCreationNotification;
+import com.ning.billing.account.api.AccountChangeEvent;
+import com.ning.billing.account.api.AccountCreationEvent;
 import com.ning.billing.account.api.user.DefaultAccountChangeNotification;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
 import com.ning.billing.util.customfield.CustomField;
@@ -134,7 +134,7 @@ public class AuditedAccountDao implements AccountDao {
 
                     saveTagsFromWithinTransaction(account, transactionalDao, context);
                     saveCustomFieldsFromWithinTransaction(account, transactionalDao, context);
-                    AccountCreationNotification creationEvent = new DefaultAccountCreationEvent(account);
+                    AccountCreationEvent creationEvent = new DefaultAccountCreationEvent(account, context.getUserToken());
                     eventBus.post(creationEvent);
                     return null;
                 }
@@ -180,7 +180,7 @@ public class AuditedAccountDao implements AccountDao {
                     saveTagsFromWithinTransaction(account, accountSqlDao, context);
                     saveCustomFieldsFromWithinTransaction(account, accountSqlDao, context);
 
-                    AccountChangeNotification changeEvent = new DefaultAccountChangeNotification(account.getId(), currentAccount, account);
+                    AccountChangeEvent changeEvent = new DefaultAccountChangeNotification(account.getId(), context.getUserToken(), currentAccount, account);
                     if (changeEvent.hasChanges()) {
                         eventBus.post(changeEvent);
                     }
diff --git a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
index 60e0a14..70beb4c 100644
--- a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
+++ b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
@@ -16,7 +16,6 @@
 
 package com.ning.billing.account.glue;
 
-import org.skife.config.ConfigurationObjectFactory;
 
 import com.google.inject.AbstractModule;
 import com.ning.billing.account.api.AccountService;
@@ -29,8 +28,6 @@ import com.ning.billing.account.dao.AuditedAccountDao;
 public class AccountModule extends AbstractModule {
 
     private void installConfig() {
-        final AccountConfig config = new ConfigurationObjectFactory(System.getProperties()).build(AccountConfig.class);
-        bind(AccountConfig.class).toInstance(config);
     }
 
     protected void installAccountDao() {
diff --git a/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
index 645124b..8761c81 100644
--- a/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
@@ -25,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
-import com.ning.billing.account.api.AccountChangeNotification;
+import com.ning.billing.account.api.AccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountChangeNotification;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
 import com.ning.billing.util.callcontext.CallContext;
@@ -46,7 +46,7 @@ public class MockAccountDao implements AccountDao {
         accounts.put(account.getId().toString(), account);
 
         try {
-            eventBus.post(new DefaultAccountCreationEvent(account));
+            eventBus.post(new DefaultAccountCreationEvent(account, null));
         }
         catch (EventBusException ex) {
             throw new RuntimeException(ex);
@@ -87,7 +87,7 @@ public class MockAccountDao implements AccountDao {
     public void update(Account account, CallContext context) {
         Account currentAccount = accounts.put(account.getId().toString(), account);
 
-        AccountChangeNotification changeEvent = new DefaultAccountChangeNotification(account.getId(), currentAccount, account);
+        AccountChangeEvent changeEvent = new DefaultAccountChangeNotification(account.getId(), null, currentAccount, account);
         if (changeEvent.hasChanges()) {
             try {
                 eventBus.post(changeEvent);

analytics/pom.xml 11(+11 -0)

diff --git a/analytics/pom.xml b/analytics/pom.xml
index cc9370a..f3bae99 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -86,6 +86,17 @@
         </dependency>
         <dependency>
             <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-ne</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-ne</artifactId>
+             <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
             <artifactId>killbill-invoice</artifactId>
             <scope>test</scope>
         </dependency>
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 3c3bab3..fb9f4d7 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
@@ -19,12 +19,12 @@ package com.ning.billing.analytics;
 import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
 import com.ning.billing.account.api.AccountApiException;
-import com.ning.billing.account.api.AccountChangeNotification;
-import com.ning.billing.account.api.AccountCreationNotification;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
-import com.ning.billing.invoice.api.InvoiceCreationNotification;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.account.api.AccountChangeEvent;
+import com.ning.billing.account.api.AccountCreationEvent;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 
 public class AnalyticsListener {
     private final BusinessSubscriptionTransitionRecorder bstRecorder;
@@ -37,7 +37,7 @@ public class AnalyticsListener {
     }
 
     @Subscribe
-    public void handleSubscriptionTransitionChange(final SubscriptionTransition event) throws AccountApiException {
+    public void handleSubscriptionTransitionChange(final SubscriptionEventTransition event) throws AccountApiException {
         switch (event.getTransitionType()) {
             // A susbcription enters either through migration or as newly created subscription
             case MIGRATE_ENTITLEMENT:
@@ -66,12 +66,12 @@ public class AnalyticsListener {
     }
 
     @Subscribe
-    public void handleAccountCreation(final AccountCreationNotification event) {
+    public void handleAccountCreation(final AccountCreationEvent event) {
         bacRecorder.accountCreated(event.getData());
     }
 
     @Subscribe
-    public void handleAccountChange(final AccountChangeNotification event) {
+    public void handleAccountChange(final AccountChangeEvent event) {
         if (!event.hasChanges()) {
             return;
         }
@@ -80,17 +80,17 @@ public class AnalyticsListener {
     }
 
     @Subscribe
-    public void handleInvoice(final InvoiceCreationNotification event) {
+    public void handleInvoice(final InvoiceCreationEvent event) {
         bacRecorder.accountUpdated(event.getAccountId());
     }
 
     @Subscribe
-    public void handlePaymentInfo(final PaymentInfo paymentInfo) {
+    public void handlePaymentInfo(final PaymentInfoEvent paymentInfo) {
         bacRecorder.accountUpdated(paymentInfo);
     }
 
     @Subscribe
-    public void handlePaymentError(final PaymentError paymentError) {
+    public void handlePaymentError(final PaymentErrorEvent paymentError) {
         // TODO - we can't tie the error back to an account yet
     }
 }
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
index 6832a2b..92c3bb0 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
@@ -26,7 +26,7 @@ import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceUserApi;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.util.tag.Tag;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
@@ -77,7 +77,7 @@ public class BusinessAccountRecorder {
      *
      * @param paymentInfo payment object (from the payment plugin)
      */
-    public void accountUpdated(final PaymentInfo paymentInfo) {
+    public void accountUpdated(final PaymentInfoEvent paymentInfo) {
         final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
         if (paymentAttempt == null) {
             return;
@@ -162,9 +162,9 @@ public class BusinessAccountRecorder {
 
             // Retrieve payments information for these invoices
             DateTime lastPaymentDate = null;
-            final List<PaymentInfo> payments = paymentApi.getPaymentInfo(invoiceIds);
+            final List<PaymentInfoEvent> payments = paymentApi.getPaymentInfo(invoiceIds);
             if (payments != null) {
-                for (final PaymentInfo payment : payments) {
+                for (final PaymentInfoEvent payment : payments) {
                     // Use the last payment method/type/country as the default one for the account
                     if (lastPaymentDate == null || payment.getCreatedDate().isAfter(lastPaymentDate)) {
                         lastPaymentDate = payment.getCreatedDate();
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
index 69b289d..82457ef 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
@@ -24,7 +24,7 @@ import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionDao;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,39 +48,39 @@ public class BusinessSubscriptionTransitionRecorder
         this.accountApi = accountApi;
     }
 
-    public void subscriptionCreated(final SubscriptionTransition created) throws AccountApiException
+    public void subscriptionCreated(final SubscriptionEventTransition created) throws AccountApiException
     {
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionCreated(created.getNextPlan());
         recordTransition(event, created);
     }
 
-    public void subscriptionRecreated(final SubscriptionTransition recreated) throws AccountApiException
+    public void subscriptionRecreated(final SubscriptionEventTransition recreated) throws AccountApiException
     {
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionRecreated(recreated.getNextPlan());
         recordTransition(event, recreated);
     }
 
 
-    public void subscriptionCancelled(final SubscriptionTransition cancelled) throws AccountApiException
+    public void subscriptionCancelled(final SubscriptionEventTransition cancelled) throws AccountApiException
     {
         // cancelled.getNextPlan() is null here - need to look at the previous one to create the correct event name
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionCancelled(cancelled.getPreviousPlan());
         recordTransition(event, cancelled);
     }
 
-    public void subscriptionChanged(final SubscriptionTransition changed) throws AccountApiException
+    public void subscriptionChanged(final SubscriptionEventTransition changed) throws AccountApiException
     {
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionChanged(changed.getNextPlan());
         recordTransition(event, changed);
     }
 
-    public void subscriptionPhaseChanged(final SubscriptionTransition phaseChanged) throws AccountApiException
+    public void subscriptionPhaseChanged(final SubscriptionEventTransition phaseChanged) throws AccountApiException
     {
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionPhaseChanged(phaseChanged.getNextPlan(), phaseChanged.getNextState());
         recordTransition(event, phaseChanged);
     }
 
-    public void recordTransition(final BusinessSubscriptionEvent event, final SubscriptionTransition transition) throws AccountApiException
+    public void recordTransition(final BusinessSubscriptionEvent event, final SubscriptionEventTransition transition) throws AccountApiException
     {
         Currency currency = null;
         String transitionKey = null;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index ebfbd9a..71cbeb1 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -37,7 +37,7 @@ import org.testng.annotations.Test;
 
 import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountCreationNotification;
+import com.ning.billing.account.api.AccountCreationEvent;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
 import com.ning.billing.analytics.AnalyticsTestModule;
@@ -65,18 +65,19 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.api.InvoiceCreationNotification;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.invoice.api.user.DefaultInvoiceCreationNotification;
 import com.ning.billing.invoice.dao.InvoiceDao;
 import com.ning.billing.invoice.model.DefaultInvoice;
 import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
+import com.ning.billing.payment.api.DefaultPaymentInfo;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.callcontext.CallContext;
@@ -135,12 +136,12 @@ public class TestAnalyticsService {
     @Inject
     private MysqlTestingHelper helper;
 
-    private SubscriptionTransition transition;
+    private SubscriptionEventTransition transition;
     private BusinessSubscriptionTransition expectedTransition;
 
-    private AccountCreationNotification accountCreationNotification;
-    private InvoiceCreationNotification invoiceCreationNotification;
-    private PaymentInfo paymentInfoNotification;
+    private AccountCreationEvent accountCreationNotification;
+    private InvoiceCreationEvent invoiceCreationNotification;
+    private PaymentInfoEvent paymentInfoNotification;
 
     @BeforeMethod(groups = "slow")
     public void cleanup() throws Exception
@@ -193,8 +194,7 @@ public class TestAnalyticsService {
         helper.initDb(paymentDdl);
         helper.initDb(utilDdl);
 
-        helper.cleanupTable("tag_definitions");
-        helper.cleanupTable("accounts");
+    	helper.cleanupAllTables();
     }
 
     private void createSubscriptionTransitionEvent(final Account account) throws EntitlementUserApiException {
@@ -230,6 +230,7 @@ public class TestAnalyticsService {
                 phase,
                 priceList,
                 1L,
+                null,
                 true
         );
         expectedTransition = new BusinessSubscriptionTransition(
@@ -244,7 +245,7 @@ public class TestAnalyticsService {
     }
 
     private void createAccountCreationEvent(final Account account) {
-        accountCreationNotification = new DefaultAccountCreationEvent(account);
+        accountCreationNotification = new DefaultAccountCreationEvent(account, null);
     }
 
     private void createInvoiceAndPaymentCreationEvents(final Account account) {
@@ -261,9 +262,9 @@ public class TestAnalyticsService {
 
         // It doesn't really matter what the events contain - the listener will go back to the db
         invoiceCreationNotification = new DefaultInvoiceCreationNotification(invoice.getId(), account.getId(),
-                INVOICE_AMOUNT, ACCOUNT_CURRENCY, clock.getUTCNow());
+                INVOICE_AMOUNT, ACCOUNT_CURRENCY, clock.getUTCNow(), null);
 
-        paymentInfoNotification = new PaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString()).setPaymentMethod(PAYMENT_METHOD).setCardCountry(CARD_COUNTRY).build();
+        paymentInfoNotification = new DefaultPaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString()).setPaymentMethod(PAYMENT_METHOD).setCardCountry(CARD_COUNTRY).build();
         final PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice.getId(), account.getId(), BigDecimal.TEN,
                 ACCOUNT_CURRENCY, clock.getUTCNow(), clock.getUTCNow(), paymentInfoNotification.getPaymentId(), 1);
         paymentDao.createPaymentAttempt(paymentAttempt, context);
@@ -292,6 +293,7 @@ public class TestAnalyticsService {
 
         // Send events and wait for the async part...
         bus.post(transition);
+
         bus.post(accountCreationNotification);
         Thread.sleep(1000);
 
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
index eaf9fed..1fe60e7 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
@@ -24,11 +24,11 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
-import com.ning.billing.catalog.api.overdue.OverdueState;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.config.api.OverdueState;
 import com.ning.billing.util.callcontext.CallContext;
 
 public class MockEntitlementUserApi implements EntitlementUserApi
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
index 0e4c2a3..306bf90 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
@@ -30,7 +30,7 @@ import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.tag.Tag;
@@ -55,13 +55,13 @@ public class MockSubscription implements Subscription
     }
 
     @Override
-    public void cancel(DateTime requestedDate, boolean eot, CallContext context)
+    public boolean cancel(DateTime requestedDate, boolean eot, CallContext context)
     {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public void changePlan(final String productName, final BillingPeriod term, final String planSet, DateTime requestedDate, CallContext context)
+    public boolean changePlan(final String productName, final BillingPeriod term, final String planSet, DateTime requestedDate, CallContext context)
     {
         throw new UnsupportedOperationException();
     }
@@ -114,7 +114,7 @@ public class MockSubscription implements Subscription
 
 
     @Override
-    public void uncancel(CallContext context) throws EntitlementUserApiException
+    public boolean uncancel(CallContext context) throws EntitlementUserApiException
     {
         throw new UnsupportedOperationException();
     }
@@ -131,7 +131,7 @@ public class MockSubscription implements Subscription
     }
 
     @Override
-    public SubscriptionTransition getPendingTransition() {
+    public SubscriptionEventTransition getPendingTransition() {
         throw new UnsupportedOperationException();
     }
 
@@ -146,7 +146,7 @@ public class MockSubscription implements Subscription
 	}
 
     @Override
-    public SubscriptionTransition getPreviousTransition() {
+    public SubscriptionEventTransition getPreviousTransition() {
         return null;
     }
 
@@ -156,7 +156,7 @@ public class MockSubscription implements Subscription
     }
 
     @Override
-    public void recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
+    public boolean recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
             throws EntitlementUserApiException {
         throw new UnsupportedOperationException();
     }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
index 13d6e05..e1c9e9d 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
@@ -164,6 +164,7 @@ public class TestAnalyticsListener
             phase,
             priceList,
             1L,
+            null,
             true
         );
     }
@@ -190,6 +191,7 @@ public class TestAnalyticsListener
             null,
             null,
             1L,
+            null,
             true
         );
     }
@@ -215,6 +217,7 @@ public class TestAnalyticsListener
             phase,
             priceList,
             1L,
+            null,
             true
         );
     }
@@ -245,6 +248,7 @@ public class TestAnalyticsListener
             phase,
             priceList,
             1L,
+            null,
             true
         );
     }
diff --git a/api/src/main/java/com/ning/billing/account/api/Account.java b/api/src/main/java/com/ning/billing/account/api/Account.java
index 65abdf1..b7f6337 100644
--- a/api/src/main/java/com/ning/billing/account/api/Account.java
+++ b/api/src/main/java/com/ning/billing/account/api/Account.java
@@ -16,7 +16,7 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.overdue.config.api.Overdueable;
 import com.ning.billing.util.customfield.Customizable;
 import com.ning.billing.util.entity.UpdatableEntity;
 import com.ning.billing.util.tag.Taggable;
diff --git a/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java b/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
index 2f8646c..d9b0053 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
@@ -19,8 +19,8 @@ package com.ning.billing.catalog.api;
 import java.util.Date;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.config.api.OverdueStateSet;
 
 
 public interface StaticCatalog {
@@ -80,6 +80,4 @@ public interface StaticCatalog {
 
     public abstract boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException;
 
-    public abstract OverdueStateSet<SubscriptionBundle> currentBundleOverdueStateSet()  throws CatalogApiException;
-
 }
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/config/CatalogConfig.java b/api/src/main/java/com/ning/billing/config/CatalogConfig.java
index 21be358..73ffd9a 100644
--- a/api/src/main/java/com/ning/billing/config/CatalogConfig.java
+++ b/api/src/main/java/com/ning/billing/config/CatalogConfig.java
@@ -19,10 +19,10 @@ package com.ning.billing.config;
 import org.skife.config.Config;
 import org.skife.config.Default;
 
-public interface CatalogConfig {
+public interface CatalogConfig extends KillbillConfig {
 
     @Config("killbill.catalog.uri")
-    @Default("jar:///com/ning/billing/irs/catalog/NingCatalog.xml")
+    @Default("jar:///com/ning/billing/irs/catalog/Catalog.xml")
     String getCatalogURI();
 
 }
diff --git a/api/src/main/java/com/ning/billing/config/EntitlementConfig.java b/api/src/main/java/com/ning/billing/config/EntitlementConfig.java
index 1b6f3e2..c73530f 100644
--- a/api/src/main/java/com/ning/billing/config/EntitlementConfig.java
+++ b/api/src/main/java/com/ning/billing/config/EntitlementConfig.java
@@ -19,21 +19,27 @@ package com.ning.billing.config;
 import org.skife.config.Config;
 import org.skife.config.Default;
 
-public interface EntitlementConfig {
+import com.google.common.annotations.VisibleForTesting;
 
+public interface EntitlementConfig extends NotificationConfig, KillbillConfig  {
+
+	@Override
     @Config("killbill.entitlement.dao.claim.time")
     @Default("60000")
     public long getDaoClaimTimeMs();
 
+	@Override
     @Config("killbill.entitlement.dao.ready.max")
     @Default("10")
     public int getDaoMaxReadyEvents();
 
+	@Override
     @Config("killbill.entitlement.engine.notifications.sleep")
     @Default("500")
     public long getNotificationSleepTimeMs();
 
+	@Override
     @Config("killbill.notifications.off")
     @Default("false")
-    public boolean isEventProcessingOff();
+    public boolean isNotificationProcessingOff();
 }
diff --git a/api/src/main/java/com/ning/billing/config/InvoiceConfig.java b/api/src/main/java/com/ning/billing/config/InvoiceConfig.java
index f56d3c2..18972eb 100644
--- a/api/src/main/java/com/ning/billing/config/InvoiceConfig.java
+++ b/api/src/main/java/com/ning/billing/config/InvoiceConfig.java
@@ -19,23 +19,27 @@ package com.ning.billing.config;
 import org.skife.config.Config;
 import org.skife.config.Default;
 
-public interface InvoiceConfig {
+public interface InvoiceConfig extends NotificationConfig, KillbillConfig  {
 
+	@Override
     @Config("killbill.invoice.dao.claim.time")
     @Default("60000")
     public long getDaoClaimTimeMs();
 
+	@Override	
     @Config("killbill.invoice.dao.ready.max")
     @Default("10")
     public int getDaoMaxReadyEvents();
 
+	@Override
     @Config("killbill.invoice.engine.notifications.sleep")
     @Default("500")
     public long getNotificationSleepTimeMs();
 
+	@Override
     @Config("killbill.notifications.off")
     @Default("false")
-    public boolean isEventProcessingOff();
+    public boolean isNotificationProcessingOff();
 
     @Config("killbill.invoice.maxNumberOfMonthsInFuture")
     @Default("36")
diff --git a/api/src/main/java/com/ning/billing/config/KillbillConfig.java b/api/src/main/java/com/ning/billing/config/KillbillConfig.java
new file mode 100644
index 0000000..336f806
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/config/KillbillConfig.java
@@ -0,0 +1,23 @@
+/* 
+ * Copyright 2010-2011 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.config;
+
+/*
+ * Marker interface for killbill config files
+ */
+public interface KillbillConfig {
+
+}
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
index a0d8e93..d59701a 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
@@ -26,7 +26,7 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 
 public interface BillingEvent extends Comparable<BillingEvent> {
 
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index ecac7aa..da8ad47 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -32,16 +32,16 @@ import com.ning.billing.util.entity.ExtendedEntity;
 
 public interface Subscription extends ExtendedEntity {
 
-    public void cancel(DateTime requestedDate, boolean eot, CallContext context)
+    public boolean cancel(DateTime requestedDate, boolean eot, CallContext context)
     throws EntitlementUserApiException;
 
-    public void uncancel(CallContext context)
+    public boolean uncancel(CallContext context)
     throws EntitlementUserApiException;
 
-    public void changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate, CallContext context)
+    public boolean changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate, CallContext context)
         throws EntitlementUserApiException;
 
-    public void recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
+    public boolean recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
         throws EntitlementUserApiException;
 
     public enum SubscriptionState {
@@ -69,7 +69,7 @@ public interface Subscription extends ExtendedEntity {
 
     public ProductCategory getCategory();
 
-    public SubscriptionTransition getPendingTransition();
+    public SubscriptionEventTransition getPendingTransition();
 
-    public SubscriptionTransition getPreviousTransition();
+    public SubscriptionEventTransition getPreviousTransition();
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
index df32c58..8794856 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
@@ -20,8 +20,8 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 
-import com.ning.billing.catalog.api.overdue.OverdueState;
-import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
 
 public interface SubscriptionBundle extends Overdueable {
 
diff --git a/api/src/main/java/com/ning/billing/invoice/api/EmptyInvoiceEvent.java b/api/src/main/java/com/ning/billing/invoice/api/EmptyInvoiceEvent.java
new file mode 100644
index 0000000..a0012a8
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/invoice/api/EmptyInvoiceEvent.java
@@ -0,0 +1,22 @@
+/* 
+ * Copyright 2010-2011 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.invoice.api;
+
+import com.ning.billing.util.bus.BusEvent;
+
+public interface EmptyInvoiceEvent extends BusEvent {
+
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueApiException.java b/api/src/main/java/com/ning/billing/overdue/OverdueApiException.java
new file mode 100644
index 0000000..7629abf
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueApiException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 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.overdue;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+
+public class OverdueApiException extends BillingExceptionBase {
+	private static final long serialVersionUID = 1L;
+
+	public OverdueApiException(Throwable cause, ErrorCode code, Object... args) {
+		super(cause, code, args);
+	}
+
+	public OverdueApiException(ErrorCode code, Object... args) {
+		super(code, args);
+	}
+
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java b/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java
index 006b18f..a785679 100644
--- a/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java
@@ -17,10 +17,10 @@
 package com.ning.billing.overdue;
 
 import com.ning.billing.catalog.api.CatalogApiException;
-import com.ning.billing.catalog.api.overdue.BillingState;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.OverdueState;
-import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
 
 public interface OverdueUserApi {
 
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index 9076256..1679f50 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -26,36 +26,36 @@ import com.ning.billing.util.callcontext.CallContext;
 
 public interface PaymentApi {
 
-    Either<PaymentError, Void> updatePaymentGateway(String accountKey, CallContext context);
+    Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey, CallContext context);
 
-    Either<PaymentError, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId);
+    Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId);
 
-    Either<PaymentError, List<PaymentMethodInfo>> getPaymentMethods(String accountKey);
+    Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey);
 
-    Either<PaymentError, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context);
+    Either<PaymentErrorEvent, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context);
 
-    Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context);
+    Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context);
 
-    Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context);
+    Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context);
 
-    List<Either<PaymentError, PaymentInfo>> createPayment(String accountKey, List<String> invoiceIds, CallContext context);
-    List<Either<PaymentError, PaymentInfo>> createPayment(Account account, List<String> invoiceIds, CallContext context);
-    Either<PaymentError, PaymentInfo> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context);
+    List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(String accountKey, List<String> invoiceIds, CallContext context);
+    List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(Account account, List<String> invoiceIds, CallContext context);
+    Either<PaymentErrorEvent, PaymentInfoEvent> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context);
 
-    List<Either<PaymentError, PaymentInfo>> createRefund(Account account, List<String> invoiceIds, CallContext context); //TODO
+    List<Either<PaymentErrorEvent, PaymentInfoEvent>> createRefund(Account account, List<String> invoiceIds, CallContext context); //TODO
 
-    Either<PaymentError, PaymentProviderAccount> getPaymentProviderAccount(String accountKey);
+    Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey);
 
-    Either<PaymentError, String> createPaymentProviderAccount(Account account, CallContext context);
+    Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account, CallContext context);
 
-    Either<PaymentError, Void> updatePaymentProviderAccountContact(String accountKey, CallContext context);
+    Either<PaymentErrorEvent, Void> updatePaymentProviderAccountContact(String accountKey, CallContext context);
 
     PaymentAttempt getPaymentAttemptForPaymentId(String id);
 
-    List<PaymentInfo> getPaymentInfo(List<String> invoiceIds);
+    List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds);
 
     List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId);
 
-    PaymentInfo getPaymentInfoForPaymentAttemptId(String paymentAttemptId);
+    PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptId);
 
 }
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentErrorEvent.java b/api/src/main/java/com/ning/billing/payment/api/PaymentErrorEvent.java
new file mode 100644
index 0000000..56cc879
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentErrorEvent.java
@@ -0,0 +1,31 @@
+/* 
+ * Copyright 2010-2011 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.api;
+
+import java.util.UUID;
+
+import com.ning.billing.util.bus.BusEvent;
+
+public interface PaymentErrorEvent extends BusEvent {
+
+    public String getType();
+
+    public String getMessage();
+
+    public UUID getInvoiceId();
+
+    public UUID getAccountId();
+}
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java b/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java
new file mode 100644
index 0000000..a93b3bb
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java
@@ -0,0 +1,54 @@
+/* 
+ * Copyright 2010-2011 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.api;
+
+import java.math.BigDecimal;
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.bus.BusEvent;
+
+public interface PaymentInfoEvent extends BusEvent {
+
+    public String getPaymentId();
+
+    public BigDecimal getAmount();
+
+    public String getBankIdentificationNumber();
+
+    public DateTime getCreatedDate();
+
+    public DateTime getEffectiveDate();
+
+    public String getPaymentNumber();
+
+    public String getPaymentMethod();
+
+    public String getCardType();
+
+    public String getCardCountry();
+
+    public String getReferenceId();
+
+    public String getPaymentMethodId();
+
+    public BigDecimal getRefundAmount();
+
+    public String getStatus();
+
+    public String getType();
+
+    public DateTime getUpdatedDate();
+}
diff --git a/api/src/main/java/com/ning/billing/util/bus/BusEvent.java b/api/src/main/java/com/ning/billing/util/bus/BusEvent.java
index 481cb74..d44e1b5 100644
--- a/api/src/main/java/com/ning/billing/util/bus/BusEvent.java
+++ b/api/src/main/java/com/ning/billing/util/bus/BusEvent.java
@@ -16,6 +16,21 @@
 
 package com.ning.billing.util.bus;
 
+import java.util.UUID;
+
 public interface BusEvent {
+	
+	public enum BusEventType {
+		ACCOUNT_CREATE,
+		ACCOUNT_CHANGE,
+		SUBSCRIPTION_TRANSITION,
+		INVOICE_EMPTY,
+		INVOICE_CREATION,
+		PAYMENT_INFO,
+		PAYMENT_ERROR
+	}
 
+	public BusEventType getBusEventType();
+	
+	public UUID getUserToken();
 }
diff --git a/api/src/main/java/com/ning/billing/util/callcontext/CallContext.java b/api/src/main/java/com/ning/billing/util/callcontext/CallContext.java
index da36f10..8be4760 100644
--- a/api/src/main/java/com/ning/billing/util/callcontext/CallContext.java
+++ b/api/src/main/java/com/ning/billing/util/callcontext/CallContext.java
@@ -16,9 +16,12 @@
 
 package com.ning.billing.util.callcontext;
 
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 
 public interface CallContext {
+	public UUID getUserToken();
     public String getUserName();
     public CallOrigin getCallOrigin();
     public UserType getUserType();
diff --git a/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequest.java b/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequest.java
new file mode 100644
index 0000000..bf67736
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequest.java
@@ -0,0 +1,19 @@
+/* 
+ * Copyright 2010-2011 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.util.userrequest;
+
+public interface CompletionUserRequest extends CompletionUserRequestNotifier, CompletionUserRequestWaiter{
+}
diff --git a/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestNotifier.java b/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestNotifier.java
new file mode 100644
index 0000000..62b9256
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestNotifier.java
@@ -0,0 +1,25 @@
+/* 
+ * Copyright 2010-2011 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.util.userrequest;
+
+import com.ning.billing.util.bus.BusEvent;
+
+public interface CompletionUserRequestNotifier {
+
+    public void notifyForCompletion();
+    
+    public void onBusEvent(BusEvent curEvent);
+}
diff --git a/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestWaiter.java b/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestWaiter.java
new file mode 100644
index 0000000..b1c35f6
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestWaiter.java
@@ -0,0 +1,48 @@
+/* 
+ * Copyright 2010-2011 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.util.userrequest;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeoutException;
+
+import com.ning.billing.account.api.AccountChangeEvent;
+import com.ning.billing.account.api.AccountCreationEvent;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
+import com.ning.billing.invoice.api.EmptyInvoiceEvent;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
+import com.ning.billing.util.bus.BusEvent;
+
+public interface CompletionUserRequestWaiter {
+
+    public List<BusEvent> waitForCompletion(final long timeoutMilliSec) throws InterruptedException, TimeoutException;
+    
+    public void onAccountCreation(final AccountCreationEvent curEvent);
+
+    public void onAccountChange(final AccountChangeEvent curEvent);
+
+    public void onSubscriptionTransition(final SubscriptionEventTransition curEvent);    
+
+    public void onInvoiceCreation(final InvoiceCreationEvent curEvent);    
+    
+    public void onEmptyInvoice(final EmptyInvoiceEvent curEvent);        
+
+    public void onPaymentInfo(final PaymentInfoEvent curEvent);    
+
+    public void onPaymentError(final PaymentErrorEvent curEvent);    
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
index 98fe90b..1ad8ccb 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
@@ -22,9 +22,6 @@ import java.io.IOException;
 import java.net.URL;
 import java.util.Set;
 
-import com.ning.billing.util.glue.CallContextModule;
-import com.ning.billing.util.glue.FieldStoreModule;
-import com.ning.billing.util.glue.TagStoreModule;
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.jdbi.v2.IDBI;
 
@@ -37,6 +34,7 @@ import com.ning.billing.beatrix.lifecycle.DefaultLifecycle;
 import com.ning.billing.beatrix.lifecycle.Lifecycle;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.config.PaymentConfig;
 import com.ning.billing.dbi.DBIProvider;
 import com.ning.billing.dbi.DbiConfig;
 import com.ning.billing.dbi.MysqlTestingHelper;
@@ -45,17 +43,18 @@ import com.ning.billing.entitlement.glue.EntitlementModule;
 import com.ning.billing.invoice.api.InvoiceService;
 import com.ning.billing.invoice.glue.InvoiceModule;
 import com.ning.billing.lifecycle.KillbillService;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.payment.api.PaymentService;
 import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
-import com.ning.billing.payment.setup.PaymentConfig;
 import com.ning.billing.payment.setup.PaymentModule;
+import com.ning.billing.util.bus.BusService;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
-import com.ning.billing.util.bus.BusService;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.FieldStoreModule;
 import com.ning.billing.util.glue.GlobalLockerModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.TagStoreModule;
 
 
 public class MockModule extends AbstractModule {
@@ -92,7 +91,6 @@ public class MockModule extends AbstractModule {
         install(new AccountModule());
         install(new CatalogModule());
         install(new EntitlementModule());
-        install(new MockOverdueAccessModule());
         install(new InvoiceModule());
         install(new PaymentMockModule());
     }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBusHandler.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBusHandler.java
index 01c3f52..ffa25e6 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBusHandler.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBusHandler.java
@@ -27,10 +27,10 @@ import org.testng.Assert;
 
 import com.google.common.base.Joiner;
 import com.google.common.eventbus.Subscribe;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
-import com.ning.billing.invoice.api.InvoiceCreationNotification;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 
 public class TestBusHandler {
 
@@ -59,7 +59,7 @@ public class TestBusHandler {
     }
 
     @Subscribe
-    public void handleEntitlementEvents(SubscriptionTransition event) {
+    public void handleEntitlementEvents(SubscriptionEventTransition event) {
         log.info(String.format("TestBusHandler Got subscription event %s", event.toString()));
         switch (event.getTransitionType()) {
         case MIGRATE_ENTITLEMENT:
@@ -96,7 +96,7 @@ public class TestBusHandler {
     }
 
     @Subscribe
-    public void handleInvoiceEvents(InvoiceCreationNotification event) {
+    public void handleInvoiceEvents(InvoiceCreationEvent event) {
         log.info(String.format("TestBusHandler Got Invoice event %s", event.toString()));
         assertEqualsNicely(NextEvent.INVOICE);
         notifyIfStackEmpty();
@@ -104,14 +104,14 @@ public class TestBusHandler {
     }
 
     @Subscribe
-    public void handlePaymentEvents(PaymentInfo event) {
+    public void handlePaymentEvents(PaymentInfoEvent event) {
         log.info(String.format("TestBusHandler Got PaymentInfo event %s", event.toString()));
         assertEqualsNicely(NextEvent.PAYMENT);
         notifyIfStackEmpty();
     }
 
     @Subscribe
-    public void handlePaymentErrorEvents(PaymentError event) {
+    public void handlePaymentErrorEvents(PaymentErrorEvent event) {
         log.info(String.format("TestBusHandler Got PaymentError event %s", event.toString()));
         //Assert.fail("Unexpected payment failure");
     }
diff --git a/beatrix/src/test/resources/catalogSample.xml b/beatrix/src/test/resources/catalogSample.xml
index fabda9d..5b7aeaf 100644
--- a/beatrix/src/test/resources/catalogSample.xml
+++ b/beatrix/src/test/resources/catalogSample.xml
@@ -184,15 +184,7 @@ Use Cases to do:
 			</priceListCase>
 		</priceList>
 	</rules>
-	
-   <overdueRules> 
-      <bundleOverdueStates>
-           <state name="Clear">
-               <isClearState>true</isClearState>
-           </state> 
-       </bundleOverdueStates>
-    </overdueRules>
-    
+
 	<plans>
 		<plan name="pistol-monthly-no-trial">
 			<product>Pistol</product>
diff --git a/bin/cleanAndInstall b/bin/cleanAndInstall
new file mode 100755
index 0000000..92ef550
--- /dev/null
+++ b/bin/cleanAndInstall
@@ -0,0 +1 @@
+bin/db-helper -a clean -d killbill; bin/db-helper -a clean -d test_killbill; mvn -Dcom.ning.billing.dbi.test.useLocalDb=true install 

bin/db-helper 149(+74 -75)

diff --git a/bin/db-helper b/bin/db-helper
index cd99dc8..cc8b746 100755
--- a/bin/db-helper
+++ b/bin/db-helper
@@ -36,122 +36,121 @@ DDL_FILE=
 CLEAN_FILE=
 
 function usage() {
-   echo -n "./db_helper "
-   echo -n " -a <create|clean|dump>"
-   echo -n " -d database_name (default = killbill)"    
-   echo -n " -u user_name (default = root)"
-   echo -n " -p password (default = root)"
-   echo -n " -t (also include test ddl)"
-   echo -n "-h this message"
-   echo
-   exit 1
+    echo -n "./db_helper "
+    echo -n " -a <create|clean|dump>"
+    echo -n " -d database_name (default = killbill)"    
+    echo -n " -u user_name (default = root)"
+    echo -n " -p password (default = root)"
+    echo -n " -t (also include test ddl)"
+    echo -n "-h this message"
+    echo
+    exit 1
 }
 
 function get_modules() {
-   local modules=`grep module $POM  | grep -v modules | cut -d '>' -f 2 | cut -d '<' -f 1`
-   echo $modules
+    local modules=`grep module $POM  | grep -v modules | cut -d '>' -f 2 | cut -d '<' -f 1`
+    echo $modules
 }
 
 function find_test_ddl() {
-
-   local modules=`get_modules`
-   local ddl_test=
-
-   local cur_ddl=
-   for m in $modules; do
-       cur_ddl=`find $m/src/test/resources/ -name ddl_test.sql 2>/dev/null`
-       ddl_test="$ddl_test $cur_ddl"
-   done
-   echo "$ddl_test"
-
+    local modules=`get_modules`
+    local ddl_test=
+    
+    local cur_ddl=
+    for m in $modules; do
+        cur_ddl=`find $m/src/test/resources/ -name ddl_test.sql 2>/dev/null`
+        ddl_test="$ddl_test $cur_ddl"
+    done
+    echo "$ddl_test"
+    
 }
 function find_src_ddl() {
-
-   local modules=`get_modules`
-   local ddl_src=
-
-   local cur_ddl=
-   for m in $modules; do
-       cur_ddl=`find $m/src/main/resources/ -name ddl.sql 2>/dev/null`
-       ddl_src="$ddl_src $cur_ddl"
-   done
-   echo "$ddl_src"
+    
+    local modules=`get_modules`
+    local ddl_src=
+    
+    local cur_ddl=
+    for m in $modules; do
+        cur_ddl=`find $m/src/main/resources/ -name ddl.sql 2>/dev/null`
+        ddl_src="$ddl_src $cur_ddl"
+    done
+    echo "$ddl_src"
 }
 
 
 function create_clean_file() {
-   local ddl_file=$1
-   local tables=`cat $ddl_file | grep -i "create table" | awk ' { print $3 } '` 
-
-   local tmp="/tmp/clean-$DATABASE.$$" 
-   echo "use $DATABASE;" >> $tmp
-   echo "" >> $tmp
-   for t in $tables; do
-       echo "truncate $t;" >> $tmp
-   done
-   echo $tmp
+    local ddl_file=$1
+    local tables=`cat $ddl_file | grep -i "create table" | awk ' { print $3 } '` 
+
+    local tmp="/tmp/clean-$DATABASE.$$" 
+    echo "use $DATABASE;" >> $tmp
+    echo "" >> $tmp
+    for t in $tables; do
+        echo "truncate $t;" >> $tmp
+    done
+    echo $tmp
 }
 
 function create_ddl_file() {
-   local ddls=`find_src_ddl`
-   local test_ddls=
-   if [ ! -z $TEST_ALSO ]; then
-       test_ddls=`find_test_ddl`
-       ddls="$ddls $test_ddls"
-   fi
-
-   local tmp="/tmp/ddl-$DATABASE.$$"
-   touch $tmp
-   echo "use $DATABASE;" >> $tmp
-   echo "" >> $tmp
-   for d in $ddls; do
-       cat $d >> $tmp
-       echo "" >> $tmp
-   done
-   echo $tmp
+    local ddls=`find_src_ddl`
+    local test_ddls=
+    if [ ! -z $TEST_ALSO ]; then
+        test_ddls=`find_test_ddl`
+        ddls="$ddls $test_ddls"
+    fi
+
+    local tmp="/tmp/ddl-$DATABASE.$$"
+    touch $tmp
+    echo "use $DATABASE;" >> $tmp
+    echo "" >> $tmp
+    for d in $ddls; do
+        cat $d >> $tmp
+        echo "" >> $tmp
+    done
+    echo $tmp
 }
 
 function cleanup() {
-   rm -f "/tmp/*.$$"
+    rm -f "/tmp/*.$$"
 }
 
 
 while getopts ":a:d:u:pt" options; do
- case $options in
-   a ) ACTION=$OPTARG;;
+  case $options in
+    a ) ACTION=$OPTARG;;
 	d ) DATABASE=$OPTARG;;
 	u ) USER=$OPTARG;;
 	p ) PWD=$OPTARG;;
 	t ) TEST_ALSO=1;;
-   h ) usage;;
-   * ) usage;;
- esac
+    h ) usage;;
+    * ) usage;;
+  esac
 done
 
 
 
 if [ -z $ACTION ]; then
-   echo "Need to specify an action <CREATE|CLEAN>"
-   usage
+    echo "Need to specify an action <CREATE|CLEAN>"
+    usage
 fi
 
 
 if [ $ACTION == "dump" ]; then
-   DDL_FILE=`create_ddl_file`
-   cat $DDL_FILE
+     DDL_FILE=`create_ddl_file`
+    cat $DDL_FILE
 fi
 
 if [ $ACTION == "create" ]; then
-   DDL_FILE=`create_ddl_file`
-   echo "Applying new schema $tmp to database $DATABASE"    
-   mysql -u $USER --password=$PWD < $DDL_FILE
+    DDL_FILE=`create_ddl_file`
+    echo "Applying new schema $tmp to database $DATABASE"    
+    mysql -u $USER --password=$PWD < $DDL_FILE
 fi
 
 if [ $ACTION == "clean" ]; then
-   DDL_FILE=`create_ddl_file` 
-   CLEAN_FILE=`create_clean_file $DDL_FILE`   
-   echo "Cleaning db tables on database $DATABASE"
-   mysql -u $USER --password=$PWD < $DDL_FILE
+    DDL_FILE=`create_ddl_file` 
+    CLEAN_FILE=`create_clean_file $DDL_FILE`   
+    echo "Cleaning db tables on database $DATABASE"
+    mysql -u $USER --password=$PWD < $DDL_FILE
 fi
 
 cleanup

bin/start-server 99(+99 -0)

diff --git a/bin/start-server b/bin/start-server
new file mode 100755
index 0000000..ce254da
--- /dev/null
+++ b/bin/start-server
@@ -0,0 +1,99 @@
+#! /usr/bin/env bash
+
+###################################################################################
+#                                                                                 #
+#                   Copyright 2010-2011 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.                                                         #
+#                                                                                 #
+###################################################################################
+
+
+HERE=`cd \`dirname $0\`; pwd`
+TOP=$HERE/..
+SERVER=$TOP/server
+
+PROPERTIES="$SERVER/src/main/resources/killbill-server.properties"
+
+DEBUG_OPTS_ECLIPSE=" -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=12345 "
+DEBUG_OPTS_ECLIPSE_WAIT=" -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=12345 "
+
+OPTS_ECLIPSE=" -Xmx2048m  -XX:+UseConcMarkSweepGC -XX:MaxPermSize=128m  "
+
+LOG="$SERVER/src/main/resources/log4j.xml"
+
+# From Argument Options
+PORT=8080
+START=
+DEBUG=
+WAIT_DEBUGGER=
+
+
+function usage() {
+    echo -n "./start-server "
+    echo -n " -s (start server)"
+    echo -n " -d (debugger turned on)"    
+    echo -n " -w (along with -d, wait for debugger before starting)"
+    echo -n " -p <port_number> default 8080"
+    echo -n "-h this message"        
+    exit 1
+}
+
+function build_properties() {
+    local opts=
+    local prop= 
+    for prop in `cat  $PROPERTIES | grep =`; do
+        local k=`echo $prop | awk '  BEGIN {FS="="} { print $1 }'`
+        local v=`echo $prop | awk 'BEGIN {FS="="} { print $2 }'`
+        opts="$opts -D$k=$v"
+    done
+    echo $opts
+}
+
+function start() {
+    local opts=`build_properties`
+    local start_cmd="mvn $opts -Dlog4j.configuration=file://$LOG -Dning.jmx.http.port=$PORT -Dxn.host.external.port=$PORT -DjettyPort=$PORT -Dxn.server.port=$PORT jetty:run"    
+
+    local debug_opts_eclipse= 
+    if [ ! -z $DEBUG ]; then
+        if  [ ! -z $WAIT_DEBUGGER ]; then
+            debug_opts_eclipse=$DEBUG_OPTS_ECLIPSE_WAIT
+        else
+            debug_opts_eclipse=$DEBUG_OPTS_ECLIPSE
+        fi
+    fi
+    export MAVEN_OPTS=" -Duser.timezone=UTC $OPTS_ECLIPSE $debug_opts_eclipse"
+    
+    echo "Starting IRS MAVEN_OPTS = $MAVEN_OPTS"
+    echo "$start_cmd"
+    cd $SERVER
+    $start_cmd
+}
+
+
+while getopts ":pswdh" options; do
+  case $options in
+	s ) START=1;;
+	d ) DEBUG=1;;
+	w ) WAIT_DEBUGGER=1;;
+	p ) PORT=$OPTARG;;
+    h ) usage;;
+    * ) usage;;
+  esac
+done
+
+if [ ! -z $START ]; then
+    start
+else
+    usage
+fi
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultCatalogService.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultCatalogService.java
index b824617..5c7b1e6 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultCatalogService.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultCatalogService.java
@@ -52,7 +52,6 @@ public class DefaultCatalogService implements KillbillService, Provider<Catalog>
     public synchronized void loadCatalog() throws ServiceException {
         if (!isInitialized) {
             try {
-            	System.out.println("Really really::" + config.getCatalogURI());
             	String url = config.getCatalogURI();
             	catalog = loader.load(url);
 
diff --git a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
index e3b24b5..a63645c 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
@@ -42,10 +42,7 @@ import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.StaticCatalog;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
-import com.ning.billing.catalog.overdue.OverdueRules;
 import com.ning.billing.catalog.rules.PlanRules;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.util.config.ValidatingConfig;
 import com.ning.billing.util.config.ValidationError;
 import com.ning.billing.util.config.ValidationErrors;
@@ -72,9 +69,6 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 	@XmlElement(name="rules", required=true)
 	private PlanRules planRules;
 
-    @XmlElement(name="overdueRules", required=false)
-    private OverdueRules overdueRules;
-
 	@XmlElementWrapper(name="plans", required=true)
 	@XmlElement(name="plan", required=true) 
 	private DefaultPlan[] plans;
@@ -247,7 +241,6 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 		validate(catalog,errors, plans);
 		priceLists.validate(catalog,errors);
 		planRules.validate(catalog, errors);
-		if(overdueRules != null) {overdueRules.validate(catalog,errors); }
 		return errors;
 	}
 
@@ -310,11 +303,6 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
         return this;
     }
 
-    protected StandaloneCatalog setOverdueRules(OverdueRules overdueRules) {
-        this.overdueRules = overdueRules;
-        return this;
-    }
-
 	@Override
 	public boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException {
 		Product product = findCurrentProduct(specifier.getProductName());
@@ -326,11 +314,4 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 				(!priceList.isRetired());
 	}
 
-    @Override
-    public OverdueStateSet<SubscriptionBundle> currentBundleOverdueStateSet()
-            throws CatalogApiException {
-         return overdueRules.getBundleStateSet();
-    }
-
-
 }
diff --git a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
index 567da32..215b142 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
@@ -33,7 +33,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.ning.billing.ErrorCode;
-import com.ning.billing.account.api.Account;
 import com.ning.billing.catalog.api.ActionPolicy;
 import com.ning.billing.catalog.api.BillingAlignment;
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -50,8 +49,6 @@ import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.StaticCatalog;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.config.ValidatingConfig;
 import com.ning.billing.util.config.ValidationErrors;
@@ -448,12 +445,4 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
 		return versionForDate(clock.getUTCNow()).canCreatePlan(specifier);
 	}
 
-    @Override
-    public OverdueStateSet<SubscriptionBundle> currentBundleOverdueStateSet()
-            throws CatalogApiException {
-        return versionForDate(clock.getUTCNow()).currentBundleOverdueStateSet();
-    }
-
-
- 
 }
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
index 09fd0e5..fa51ed1 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
@@ -18,8 +18,6 @@ package com.ning.billing.catalog;
 
 import java.util.Date;
 
-import com.ning.billing.catalog.overdue.MockOverdueRules;
-import com.ning.billing.catalog.overdue.OverdueRules;
 import com.ning.billing.catalog.rules.CaseCancelPolicy;
 import com.ning.billing.catalog.rules.CaseChangePlanAlignment;
 import com.ning.billing.catalog.rules.CaseChangePlanPolicy;
@@ -35,13 +33,7 @@ public class MockCatalog extends StandaloneCatalog {
 		setPlans((DefaultPlan[])MockPlan.createAll());
 		populateRules();
 		populatePriceLists();
-		setOverdueRules();
 	}
-	
-	public void setOverdueRules() {
-	    OverdueRules overdueRules = new MockOverdueRules();
-        setOverdueRules(overdueRules);  
-    }
 
     public void populateRules(){
 		setPlanRules(new PlanRules());
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
index 5612fb6..ca17050 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
@@ -67,16 +67,7 @@
             </createAlignmentCase>
         </createAlignment>
 	</rules>
-	
-    <overdueRules>
-       <bundleOverdueStates>
-           <state name="ClearBundle">
-               <isClearState>true</isClearState>
-           </state>
-       </bundleOverdueStates>
-    </overdueRules>
-
-
+ 
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
index 77ea3bf..0e650f1 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
@@ -68,14 +68,6 @@
         </createAlignment>
 	</rules>
 
-    <overdueRules>
-        <bundleOverdueStates>
-           <state name="ClearBundle">
-               <isClearState>true</isClearState>
-           </state>
-       </bundleOverdueStates>
-    </overdueRules>
-
 	<plans>
 		<plan name="pistol-monthly">
 			<effectiveDateForExistingSubscriptons>2011-02-14T00:00:00+00:00</effectiveDateForExistingSubscriptons>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
index 9c98563..ccbd964 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
@@ -68,15 +68,6 @@
         </createAlignment>
 	</rules>
 
-    <overdueRules>
-        <bundleOverdueStates>
-           <state name="ClearBundle">
-               <isClearState>true</isClearState>
-           </state>
-       </bundleOverdueStates>
-    </overdueRules>
-
-
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
diff --git a/catalog/src/test/resources/WeaponsHire.xml b/catalog/src/test/resources/WeaponsHire.xml
index 8fbb1f5..4a895b0 100644
--- a/catalog/src/test/resources/WeaponsHire.xml
+++ b/catalog/src/test/resources/WeaponsHire.xml
@@ -171,14 +171,6 @@ Use Cases to do:
 		</priceList>
 	</rules> 
 	
-	<overdueRules> 
-       <bundleOverdueStates>
-	       <state name="ClearBundles">
-               <isClearState>true</isClearState>
-           </state> 
-	   </bundleOverdueStates>
-	</overdueRules>
-
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
diff --git a/catalog/src/test/resources/WeaponsHireSmall.xml b/catalog/src/test/resources/WeaponsHireSmall.xml
index 2c363c0..21a9f08 100644
--- a/catalog/src/test/resources/WeaponsHireSmall.xml
+++ b/catalog/src/test/resources/WeaponsHireSmall.xml
@@ -70,15 +70,6 @@
             </createAlignmentCase>
         </createAlignment>
 	</rules>
-	
-	 <overdueRules>
-        <bundleOverdueStates>
-           <state name="ClearBundle">
-               <isClearState>true</isClearState>
-           </state>
-       </bundleOverdueStates>
-    </overdueRules>
-	
 
 	<plans>
 		<plan name="pistol-monthly">

doc/api.html 91(+91 -0)

diff --git a/doc/api.html b/doc/api.html
new file mode 100644
index 0000000..f44a165
--- /dev/null
+++ b/doc/api.html
@@ -0,0 +1,91 @@
+<!-- ~ Copyright 2010-2011 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. -->
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>Collector core | Dwarf</title>
+    <meta name="user guide" content="">
+    <meta name="author" content="Stephane Brossier">
+
+    <!--[if lt IE 9]>
+    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
+    <![endif]-->
+
+    <link rel=stylesheet type="text/css" href="css/bootstrap.min.css">
+    <link rel=stylesheet type="text/css" href="css/prettify.css">
+    <link rel=stylesheet type="text/css" href="css/killbill.css">
+    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+    <script src="js/prettify.js"></script>
+    <script src="js/bootstrap-dropdown.js"></script>
+
+    <script type="text/javascript">
+      var _gaq = _gaq || [];
+      _gaq.push(['_setAccount', 'UA-19297396-1']);
+      _gaq.push(['_trackPageview']);
+      (function() {
+        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+      })();
+    </script>
+</head>
+
+<body onload="prettyPrint();">
+
+    <div class="topbar" data-dropdown="dropdown">
+        <div class="topbar-inner">
+            <div class="container-fluid">
+                <a class="brand" href="../index.html">Killbill</a>
+                <ul class="nav">
+                    <li><a href="user.html">User Guide</a></li>
+                    <li><a href="setup.html">Setup/Installation</a></li>   
+                    <li class="active"><a href="user.html">APIs</a></li>
+                    <li><a href="design.html">Design</a></li>                                                
+                    <li><a href="http://groups.google.com/group/killbill-users">Mailing List</a></li>
+                </ul>
+                <ul class="nav secondary-nav">
+                    <li class="dropdown">
+                        <a href="#" class="dropdown-toggle">Maven sites</a>
+                        <ul class="dropdown-menu">
+                            <li><a href="http://sbrossie.github.com/killbill" target="_blank">Killbill</a></li>
+                        </ul>
+                    </li>
+                </ul>
+                <ul class="nav secondary-nav">
+                    <li class="dropdown">
+                        <a href="#" class="dropdown-toggle">Github projects</a>
+                        <ul class="dropdown-menu">
+                            <li><a href="http://github.com/ning/killbill" target="_blank">Killbill</a></li>
+                        </ul>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+    <div class="container-fluid">
+        <div class="sidebar">
+            <div class="well">
+                <h5>Setup</h5>
+                <ul>
+                    <li><a href="#overview">Prerequisite</a></li>
+                    <li><a href="#Details">Installation</a></li>
+                </ul>
+            </div>
+        </div>
+        <div class="content">
+            <h2 class="overview">Overview</h2>
+                Bla bla get me prerequisite
+            <h2 class="details">Details</h2>
+                    details  
+        </div>
+    </div>
+</body>
+ 
diff --git a/doc/css/bootstrap.min.css b/doc/css/bootstrap.min.css
new file mode 100644
index 0000000..75e85d3
--- /dev/null
+++ b/doc/css/bootstrap.min.css
@@ -0,0 +1,356 @@
+html,body{margin:0;padding:0;}
+h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,cite,code,del,dfn,em,img,q,s,samp,small,strike,strong,sub,sup,tt,var,dd,dl,dt,li,ol,ul,fieldset,form,label,legend,button,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;font-weight:normal;font-style:normal;font-size:100%;line-height:1;font-family:inherit;}
+table{border-collapse:collapse;border-spacing:0;}
+ol,ul{list-style:none;}
+q:before,q:after,blockquote:before,blockquote:after{content:"";}
+html{overflow-y:scroll;font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
+a:focus{outline:thin dotted;}
+a:hover,a:active{outline:0;}
+article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
+audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
+audio:not([controls]){display:none;}
+sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}
+sup{top:-0.5em;}
+sub{bottom:-0.25em;}
+img{border:0;-ms-interpolation-mode:bicubic;}
+button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;}
+button,input{line-height:normal;*overflow:visible;}
+button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
+button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
+input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
+input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}
+textarea{overflow:auto;vertical-align:top;}
+body{background-color:#ffffff;margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;color:#404040;}
+.container{width:940px;margin-left:auto;margin-right:auto;zoom:1;}.container:before,.container:after{display:table;content:"";zoom:1;}
+.container:after{clear:both;}
+.container-fluid{position:relative;min-width:940px;padding-left:20px;padding-right:20px;zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";zoom:1;}
+.container-fluid:after{clear:both;}
+.container-fluid>.sidebar{position:absolute;top:0;left:20px;width:220px;}
+.container-fluid>.content{margin-left:240px;}
+a{color:#0069d6;text-decoration:none;line-height:inherit;font-weight:inherit;}a:hover{color:#00438a;text-decoration:underline;}
+.pull-right{float:right;}
+.pull-left{float:left;}
+.hide{display:none;}
+.show{display:block;}
+.row{zoom:1;margin-left:-20px;}.row:before,.row:after{display:table;content:"";zoom:1;}
+.row:after{clear:both;}
+.row>[class*="span"]{display:inline;float:left;margin-left:20px;}
+.span1{width:40px;}
+.span2{width:100px;}
+.span3{width:160px;}
+.span4{width:220px;}
+.span5{width:280px;}
+.span6{width:340px;}
+.span7{width:400px;}
+.span8{width:460px;}
+.span9{width:520px;}
+.span10{width:580px;}
+.span11{width:640px;}
+.span12{width:700px;}
+.span13{width:760px;}
+.span14{width:820px;}
+.span15{width:880px;}
+.span16{width:940px;}
+.span17{width:1000px;}
+.span18{width:1060px;}
+.span19{width:1120px;}
+.span20{width:1180px;}
+.span21{width:1240px;}
+.span22{width:1300px;}
+.span23{width:1360px;}
+.span24{width:1420px;}
+.row >.offset1{margin-left:80px;}
+.row >.offset2{margin-left:140px;}
+.row >.offset3{margin-left:200px;}
+.row >.offset4{margin-left:260px;}
+.row >.offset5{margin-left:320px;}
+.row >.offset6{margin-left:380px;}
+.row >.offset7{margin-left:440px;}
+.row >.offset8{margin-left:500px;}
+.row >.offset9{margin-left:560px;}
+.row >.offset10{margin-left:620px;}
+.row >.offset11{margin-left:680px;}
+.row >.offset12{margin-left:740px;}
+.span-one-third{width:300px;}
+.span-two-thirds{width:620px;}
+.offset-one-third{margin-left:340px;}
+.offset-two-thirds{margin-left:660px;}
+p{font-size:13px;font-weight:normal;line-height:18px;margin-bottom:9px;}p small{font-size:11px;color:#bfbfbf;}
+h1,h2,h3,h4,h5,h6{font-weight:bold;color:#404040;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:#bfbfbf;}
+h1{margin-bottom:18px;font-size:30px;line-height:36px;}h1 small{font-size:18px;}
+h2{font-size:24px;line-height:36px;}h2 small{font-size:14px;}
+h3,h4,h5,h6{line-height:36px;}
+h3{font-size:18px;}h3 small{font-size:14px;}
+h4{font-size:16px;}h4 small{font-size:12px;}
+h5{font-size:14px;}
+h6{font-size:13px;color:#bfbfbf;text-transform:uppercase;}
+ul,ol{margin:0 0 18px 25px;}
+ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
+ul{list-style:disc;}
+ol{list-style:decimal;}
+li{line-height:18px;color:#808080;}
+ul.unstyled{list-style:none;margin-left:0;}
+dl{margin-bottom:18px;}dl dt,dl dd{line-height:18px;}
+dl dt{font-weight:bold;}
+dl dd{margin-left:9px;}
+hr{margin:20px 0 19px;border:0;border-bottom:1px solid #eee;}
+strong{font-style:inherit;font-weight:bold;}
+em{font-style:italic;font-weight:inherit;line-height:inherit;}
+.muted{color:#bfbfbf;}
+blockquote{margin-bottom:18px;border-left:5px solid #eee;padding-left:15px;}blockquote p{font-size:14px;font-weight:300;line-height:18px;margin-bottom:0;}
+blockquote small{display:block;font-size:12px;font-weight:300;line-height:18px;color:#bfbfbf;}blockquote small:before{content:'\2014 \00A0';}
+address{display:block;line-height:18px;margin-bottom:18px;}
+code,pre{padding:0 3px 2px;font-family:Monaco, Andale Mono, Courier New, monospace;font-size:12px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+code{background-color:#fee9cc;color:rgba(0, 0, 0, 0.75);padding:1px 3px;}
+pre{background-color:#f5f5f5;display:block;padding:8.5px;margin:0 0 18px;line-height:18px;font-size:12px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;white-space:pre;white-space:pre-wrap;word-wrap:break-word;}
+form{margin-bottom:18px;}
+fieldset{margin-bottom:18px;padding-top:18px;}fieldset legend{display:block;padding-left:150px;font-size:19.5px;line-height:1;color:#404040;*padding:0 0 5px 145px;*line-height:1.5;}
+form .clearfix{margin-bottom:18px;zoom:1;}form .clearfix:before,form .clearfix:after{display:table;content:"";zoom:1;}
+form .clearfix:after{clear:both;}
+label,input,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:normal;}
+label{padding-top:6px;font-size:13px;line-height:18px;float:left;width:130px;text-align:right;color:#404040;}
+form .input{margin-left:150px;}
+input[type=checkbox],input[type=radio]{cursor:pointer;}
+input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;font-size:13px;line-height:18px;color:#808080;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+select{padding:initial;}
+input[type=checkbox],input[type=radio]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:none;}
+input[type=file]{background-color:#ffffff;padding:initial;border:initial;line-height:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+input[type=button],input[type=reset],input[type=submit]{width:auto;height:auto;}
+select,input[type=file]{height:27px;*height:auto;line-height:27px;*margin-top:4px;}
+select[multiple]{height:inherit;background-color:#ffffff;}
+textarea{height:auto;}
+.uneditable-input{background-color:#ffffff;display:block;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
+:-moz-placeholder{color:#bfbfbf;}
+::-webkit-input-placeholder{color:#bfbfbf;}
+input,textarea{-webkit-transform-style:preserve-3d;-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);}
+input:focus,textarea:focus{outline:0;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);}
+input[type=file]:focus,input[type=checkbox]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:1px dotted #666;}
+form .clearfix.error>label,form .clearfix.error .help-block,form .clearfix.error .help-inline{color:#b94a48;}
+form .clearfix.error input,form .clearfix.error textarea{color:#b94a48;border-color:#ee5f5b;}form .clearfix.error input:focus,form .clearfix.error textarea:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
+form .clearfix.error .input-prepend .add-on,form .clearfix.error .input-append .add-on{color:#b94a48;background-color:#fce6e6;border-color:#b94a48;}
+form .clearfix.warning>label,form .clearfix.warning .help-block,form .clearfix.warning .help-inline{color:#c09853;}
+form .clearfix.warning input,form .clearfix.warning textarea{color:#c09853;border-color:#ccae64;}form .clearfix.warning input:focus,form .clearfix.warning textarea:focus{border-color:#be9a3f;-webkit-box-shadow:0 0 6px #e5d6b1;-moz-box-shadow:0 0 6px #e5d6b1;box-shadow:0 0 6px #e5d6b1;}
+form .clearfix.warning .input-prepend .add-on,form .clearfix.warning .input-append .add-on{color:#c09853;background-color:#d2b877;border-color:#c09853;}
+form .clearfix.success>label,form .clearfix.success .help-block,form .clearfix.success .help-inline{color:#468847;}
+form .clearfix.success input,form .clearfix.success textarea{color:#468847;border-color:#57a957;}form .clearfix.success input:focus,form .clearfix.success textarea:focus{border-color:#458845;-webkit-box-shadow:0 0 6px #9acc9a;-moz-box-shadow:0 0 6px #9acc9a;box-shadow:0 0 6px #9acc9a;}
+form .clearfix.success .input-prepend .add-on,form .clearfix.success .input-append .add-on{color:#468847;background-color:#bcddbc;border-color:#468847;}
+.input-mini,input.mini,textarea.mini,select.mini{width:60px;}
+.input-small,input.small,textarea.small,select.small{width:90px;}
+.input-medium,input.medium,textarea.medium,select.medium{width:150px;}
+.input-large,input.large,textarea.large,select.large{width:210px;}
+.input-xlarge,input.xlarge,textarea.xlarge,select.xlarge{width:270px;}
+.input-xxlarge,input.xxlarge,textarea.xxlarge,select.xxlarge{width:530px;}
+textarea.xxlarge{overflow-y:auto;}
+input.span1,textarea.span1{display:inline-block;float:none;width:30px;margin-left:0;}
+input.span2,textarea.span2{display:inline-block;float:none;width:90px;margin-left:0;}
+input.span3,textarea.span3{display:inline-block;float:none;width:150px;margin-left:0;}
+input.span4,textarea.span4{display:inline-block;float:none;width:210px;margin-left:0;}
+input.span5,textarea.span5{display:inline-block;float:none;width:270px;margin-left:0;}
+input.span6,textarea.span6{display:inline-block;float:none;width:330px;margin-left:0;}
+input.span7,textarea.span7{display:inline-block;float:none;width:390px;margin-left:0;}
+input.span8,textarea.span8{display:inline-block;float:none;width:450px;margin-left:0;}
+input.span9,textarea.span9{display:inline-block;float:none;width:510px;margin-left:0;}
+input.span10,textarea.span10{display:inline-block;float:none;width:570px;margin-left:0;}
+input.span11,textarea.span11{display:inline-block;float:none;width:630px;margin-left:0;}
+input.span12,textarea.span12{display:inline-block;float:none;width:690px;margin-left:0;}
+input.span13,textarea.span13{display:inline-block;float:none;width:750px;margin-left:0;}
+input.span14,textarea.span14{display:inline-block;float:none;width:810px;margin-left:0;}
+input.span15,textarea.span15{display:inline-block;float:none;width:870px;margin-left:0;}
+input.span16,textarea.span16{display:inline-block;float:none;width:930px;margin-left:0;}
+input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;}
+.actions{background:#f5f5f5;margin-top:18px;margin-bottom:18px;padding:17px 20px 18px 150px;border-top:1px solid #ddd;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.actions .secondary-action{float:right;}.actions .secondary-action a{line-height:30px;}.actions .secondary-action a:hover{text-decoration:underline;}
+.help-inline,.help-block{font-size:13px;line-height:18px;color:#bfbfbf;}
+.help-inline{padding-left:5px;*position:relative;*top:-5px;}
+.help-block{display:block;max-width:600px;}
+.inline-inputs{color:#808080;}.inline-inputs span{padding:0 2px 0 1px;}
+.input-prepend input,.input-append input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
+.input-prepend .add-on,.input-append .add-on{position:relative;background:#f5f5f5;border:1px solid #ccc;z-index:2;float:left;display:block;width:auto;min-width:16px;height:18px;padding:4px 4px 4px 5px;margin-right:-1px;font-weight:normal;line-height:18px;color:#bfbfbf;text-align:center;text-shadow:0 1px 0 #ffffff;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.input-prepend .active,.input-append .active{background:#a9dba9;border-color:#46a546;}
+.input-prepend .add-on{*margin-top:1px;}
+.input-append input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.input-append .add-on{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;margin-right:0;margin-left:-1px;}
+.inputs-list{margin:0 0 5px;width:100%;}.inputs-list li{display:block;padding:0;width:100%;}
+.inputs-list label{display:block;float:none;width:auto;padding:0;margin-left:20px;line-height:18px;text-align:left;white-space:normal;}.inputs-list label strong{color:#808080;}
+.inputs-list label small{font-size:11px;font-weight:normal;}
+.inputs-list .inputs-list{margin-left:25px;margin-bottom:10px;padding-top:0;}
+.inputs-list:first-child{padding-top:6px;}
+.inputs-list li+li{padding-top:2px;}
+.inputs-list input[type=radio],.inputs-list input[type=checkbox]{margin-bottom:0;margin-left:-20px;float:left;}
+.form-stacked{padding-left:20px;}.form-stacked fieldset{padding-top:9px;}
+.form-stacked legend{padding-left:0;}
+.form-stacked label{display:block;float:none;width:auto;font-weight:bold;text-align:left;line-height:20px;padding-top:0;}
+.form-stacked .clearfix{margin-bottom:9px;}.form-stacked .clearfix div.input{margin-left:0;}
+.form-stacked .inputs-list{margin-bottom:0;}.form-stacked .inputs-list li{padding-top:0;}.form-stacked .inputs-list li label{font-weight:normal;padding-top:0;}
+.form-stacked div.clearfix.error{padding-top:10px;padding-bottom:10px;padding-left:10px;margin-top:0;margin-left:-10px;}
+.form-stacked .actions{margin-left:-20px;padding-left:20px;}
+table{width:100%;margin-bottom:18px;padding:0;font-size:13px;border-collapse:collapse;}table th,table td{padding:10px 10px 9px;line-height:18px;text-align:left;}
+table th{padding-top:9px;font-weight:bold;vertical-align:middle;}
+table td{vertical-align:top;border-top:1px solid #ddd;}
+table tbody th{border-top:1px solid #ddd;vertical-align:top;}
+.condensed-table th,.condensed-table td{padding:5px 5px 4px;}
+.bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.bordered-table th+th,.bordered-table td+td,.bordered-table th+td{border-left:1px solid #ddd;}
+.bordered-table thead tr:first-child th:first-child,.bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
+.bordered-table thead tr:first-child th:last-child,.bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
+.bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
+.bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
+table .span1{width:20px;}
+table .span2{width:60px;}
+table .span3{width:100px;}
+table .span4{width:140px;}
+table .span5{width:180px;}
+table .span6{width:220px;}
+table .span7{width:260px;}
+table .span8{width:300px;}
+table .span9{width:340px;}
+table .span10{width:380px;}
+table .span11{width:420px;}
+table .span12{width:460px;}
+table .span13{width:500px;}
+table .span14{width:540px;}
+table .span15{width:580px;}
+table .span16{width:620px;}
+.zebra-striped tbody tr:nth-child(odd) td,.zebra-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
+.zebra-striped tbody tr:hover td,.zebra-striped tbody tr:hover th{background-color:#f5f5f5;}
+table .header{cursor:pointer;}table .header:after{content:"";float:right;margin-top:7px;border-width:0 4px 4px;border-style:solid;border-color:#000 transparent;visibility:hidden;}
+table .headerSortUp,table .headerSortDown{background-color:rgba(141, 192, 219, 0.25);text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);}
+table .header:hover:after{visibility:visible;}
+table .headerSortDown:after,table .headerSortDown:hover:after{visibility:visible;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;}
+table .headerSortUp:after{border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000;visibility:visible;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;}
+table .blue{color:#049cdb;border-bottom-color:#049cdb;}
+table .headerSortUp.blue,table .headerSortDown.blue{background-color:#ade6fe;}
+table .green{color:#46a546;border-bottom-color:#46a546;}
+table .headerSortUp.green,table .headerSortDown.green{background-color:#cdeacd;}
+table .red{color:#9d261d;border-bottom-color:#9d261d;}
+table .headerSortUp.red,table .headerSortDown.red{background-color:#f4c8c5;}
+table .yellow{color:#ffc40d;border-bottom-color:#ffc40d;}
+table .headerSortUp.yellow,table .headerSortDown.yellow{background-color:#fff6d9;}
+table .orange{color:#f89406;border-bottom-color:#f89406;}
+table .headerSortUp.orange,table .headerSortDown.orange{background-color:#fee9cc;}
+table .purple{color:#7a43b6;border-bottom-color:#7a43b6;}
+table .headerSortUp.purple,table .headerSortDown.purple{background-color:#e2d5f0;}
+.topbar{height:40px;position:fixed;top:0;left:0;right:0;z-index:10000;overflow:visible;}.topbar a{color:#bfbfbf;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}
+.topbar h3 a:hover,.topbar .brand:hover,.topbar ul .active>a{background-color:#333;background-color:rgba(255, 255, 255, 0.05);color:#ffffff;text-decoration:none;}
+.topbar h3{position:relative;}
+.topbar h3 a,.topbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;color:#ffffff;font-size:20px;font-weight:200;line-height:1;}
+.topbar p{margin:0;line-height:40px;}.topbar p a:hover{background-color:transparent;color:#ffffff;}
+.topbar form{float:left;margin:5px 0 0 0;position:relative;filter:alpha(opacity=100);-khtml-opacity:1;-moz-opacity:1;opacity:1;}
+.topbar form.pull-right{float:right;}
+.topbar input{background-color:#444;background-color:rgba(255, 255, 255, 0.3);font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:normal;font-weight:13px;line-height:1;padding:4px 9px;color:#ffffff;color:rgba(255, 255, 255, 0.75);border:1px solid #111;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.25);-webkit-transform-style:preserve-3d;-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.topbar input:-moz-placeholder{color:#e6e6e6;}
+.topbar input::-webkit-input-placeholder{color:#e6e6e6;}
+.topbar input:hover{background-color:#bfbfbf;background-color:rgba(255, 255, 255, 0.5);color:#ffffff;}
+.topbar input:focus,.topbar input.focused{outline:0;background-color:#ffffff;color:#404040;text-shadow:0 1px 0 #ffffff;border:0;padding:5px 10px;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);}
+.topbar-inner,.topbar .fill{background-color:#222;background-color:#222222;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#333333), to(#222222));background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #333333), color-stop(100%, #222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);}
+.topbar div>ul,.nav{display:block;float:left;margin:0 10px 0 0;position:relative;left:0;}.topbar div>ul>li,.nav>li{display:block;float:left;}
+.topbar div>ul a,.nav a{display:block;float:none;padding:10px 10px 11px;line-height:19px;text-decoration:none;}.topbar div>ul a:hover,.nav a:hover{color:#ffffff;text-decoration:none;}
+.topbar div>ul .active>a,.nav .active>a{background-color:#222;background-color:rgba(0, 0, 0, 0.5);}
+.topbar div>ul.secondary-nav,.nav.secondary-nav{float:right;margin-left:10px;margin-right:0;}.topbar div>ul.secondary-nav .menu-dropdown,.nav.secondary-nav .menu-dropdown,.topbar div>ul.secondary-nav .dropdown-menu,.nav.secondary-nav .dropdown-menu{right:0;border:0;}
+.topbar div>ul a.menu:hover,.nav a.menu:hover,.topbar div>ul li.open .menu,.nav li.open .menu,.topbar div>ul .dropdown-toggle:hover,.nav .dropdown-toggle:hover,.topbar div>ul .dropdown.open .dropdown-toggle,.nav .dropdown.open .dropdown-toggle{background:#444;background:rgba(255, 255, 255, 0.05);}
+.topbar div>ul .menu-dropdown,.nav .menu-dropdown,.topbar div>ul .dropdown-menu,.nav .dropdown-menu{background-color:#333;}.topbar div>ul .menu-dropdown a.menu,.nav .menu-dropdown a.menu,.topbar div>ul .dropdown-menu a.menu,.nav .dropdown-menu a.menu,.topbar div>ul .menu-dropdown .dropdown-toggle,.nav .menu-dropdown .dropdown-toggle,.topbar div>ul .dropdown-menu .dropdown-toggle,.nav .dropdown-menu .dropdown-toggle{color:#ffffff;}.topbar div>ul .menu-dropdown a.menu.open,.nav .menu-dropdown a.menu.open,.topbar div>ul .dropdown-menu a.menu.open,.nav .dropdown-menu a.menu.open,.topbar div>ul .menu-dropdown .dropdown-toggle.open,.nav .menu-dropdown .dropdown-toggle.open,.topbar div>ul .dropdown-menu .dropdown-toggle.open,.nav .dropdown-menu .dropdown-toggle.open{background:#444;background:rgba(255, 255, 255, 0.05);}
+.topbar div>ul .menu-dropdown li a,.nav .menu-dropdown li a,.topbar div>ul .dropdown-menu li a,.nav .dropdown-menu li a{color:#999;text-shadow:0 1px 0 rgba(0, 0, 0, 0.5);}.topbar div>ul .menu-dropdown li a:hover,.nav .menu-dropdown li a:hover,.topbar div>ul .dropdown-menu li a:hover,.nav .dropdown-menu li a:hover{background-color:#191919;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#292929), to(#191919));background-image:-moz-linear-gradient(top, #292929, #191919);background-image:-ms-linear-gradient(top, #292929, #191919);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #292929), color-stop(100%, #191919));background-image:-webkit-linear-gradient(top, #292929, #191919);background-image:-o-linear-gradient(top, #292929, #191919);background-image:linear-gradient(top, #292929, #191919);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#292929', endColorstr='#191919', GradientType=0);color:#ffffff;}
+.topbar div>ul .menu-dropdown .active a,.nav .menu-dropdown .active a,.topbar div>ul .dropdown-menu .active a,.nav .dropdown-menu .active a{color:#ffffff;}
+.topbar div>ul .menu-dropdown .divider,.nav .menu-dropdown .divider,.topbar div>ul .dropdown-menu .divider,.nav .dropdown-menu .divider{background-color:#222;border-color:#444;}
+.topbar ul .menu-dropdown li a,.topbar ul .dropdown-menu li a{padding:4px 15px;}
+li.menu,.dropdown{position:relative;}
+a.menu:after,.dropdown-toggle:after{width:0;height:0;display:inline-block;content:"&darr;";text-indent:-99999px;vertical-align:top;margin-top:8px;margin-left:4px;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #ffffff;filter:alpha(opacity=50);-khtml-opacity:0.5;-moz-opacity:0.5;opacity:0.5;}
+.menu-dropdown,.dropdown-menu{background-color:#ffffff;float:left;display:none;position:absolute;top:40px;z-index:900;min-width:160px;max-width:220px;_width:160px;margin-left:0;margin-right:0;padding:6px 0;zoom:1;border-color:#999;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:0 1px 1px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);box-shadow:0 2px 4px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.menu-dropdown li,.dropdown-menu li{float:none;display:block;background-color:none;}
+.menu-dropdown .divider,.dropdown-menu .divider{height:1px;margin:5px 0;overflow:hidden;background-color:#eee;border-bottom:1px solid #ffffff;}
+.topbar .dropdown-menu a,.dropdown-menu a{display:block;padding:4px 15px;clear:both;font-weight:normal;line-height:18px;color:#808080;text-shadow:0 1px 0 #ffffff;}.topbar .dropdown-menu a:hover,.dropdown-menu a:hover,.topbar .dropdown-menu a.hover,.dropdown-menu a.hover{background-color:#dddddd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#eeeeee), to(#dddddd));background-image:-moz-linear-gradient(top, #eeeeee, #dddddd);background-image:-ms-linear-gradient(top, #eeeeee, #dddddd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #eeeeee), color-stop(100%, #dddddd));background-image:-webkit-linear-gradient(top, #eeeeee, #dddddd);background-image:-o-linear-gradient(top, #eeeeee, #dddddd);background-image:linear-gradient(top, #eeeeee, #dddddd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0);color:#404040;text-decoration:none;-webkit-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.025),inset 0 -1px rgba(0, 0, 0, 0.025);}
+.open .menu,.dropdown.open .menu,.open .dropdown-toggle,.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);}
+.open .menu-dropdown,.dropdown.open .menu-dropdown,.open .dropdown-menu,.dropdown.open .dropdown-menu{display:block;}
+.tabs,.pills{margin:0 0 18px;padding:0;list-style:none;zoom:1;}.tabs:before,.pills:before,.tabs:after,.pills:after{display:table;content:"";zoom:1;}
+.tabs:after,.pills:after{clear:both;}
+.tabs>li,.pills>li{float:left;}.tabs>li>a,.pills>li>a{display:block;}
+.tabs{border-color:#ddd;border-style:solid;border-width:0 0 1px;}.tabs>li{position:relative;margin-bottom:-1px;}.tabs>li>a{padding:0 15px;margin-right:2px;line-height:34px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.tabs>li>a:hover{text-decoration:none;background-color:#eee;border-color:#eee #eee #ddd;}
+.tabs .active>a,.tabs .active>a:hover{color:#808080;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
+.tabs .menu-dropdown,.tabs .dropdown-menu{top:35px;border-width:1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
+.tabs a.menu:after,.tabs .dropdown-toggle:after{border-top-color:#999;margin-top:15px;margin-left:5px;}
+.tabs li.open.menu .menu,.tabs .open.dropdown .dropdown-toggle{border-color:#999;}
+.tabs li.open a.menu:after,.tabs .dropdown.open .dropdown-toggle:after{border-top-color:#555;}
+.pills a{margin:5px 3px 5px 0;padding:0 15px;line-height:30px;text-shadow:0 1px 1px #ffffff;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}.pills a:hover{color:#ffffff;text-decoration:none;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#00438a;}
+.pills .active a{color:#ffffff;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#0069d6;}
+.pills-vertical>li{float:none;}
+.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
+.tab-content>.active,.pill-content>.active{display:block;}
+.breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#f5f5f5;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ffffff), to(#f5f5f5));background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline;text-shadow:0 1px 0 #ffffff;}
+.breadcrumb .divider{padding:0 5px;color:#bfbfbf;}
+.breadcrumb .active a{color:#404040;}
+.hero-unit{background-color:#f5f5f5;margin-bottom:30px;padding:60px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;}
+.hero-unit p{font-size:18px;font-weight:200;line-height:27px;}
+footer{margin-top:17px;padding-top:17px;border-top:1px solid #eee;}
+.page-header{margin-bottom:17px;border-bottom:1px solid #ddd;-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}.page-header h1{margin-bottom:8px;}
+.btn.danger,.alert-message.danger,.btn.danger:hover,.alert-message.danger:hover,.btn.error,.alert-message.error,.btn.error:hover,.alert-message.error:hover,.btn.success,.alert-message.success,.btn.success:hover,.alert-message.success:hover,.btn.info,.alert-message.info,.btn.info:hover,.alert-message.info:hover{color:#ffffff;}
+.btn .close,.alert-message .close{font-family:Arial,sans-serif;line-height:18px;}
+.btn.danger,.alert-message.danger,.btn.error,.alert-message.error{background-color:#c43c35;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#c43c35 #c43c35 #882a25;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
+.btn.success,.alert-message.success{background-color:#57a957;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#57a957 #57a957 #3d773d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
+.btn.info,.alert-message.info{background-color:#339bb9;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#339bb9 #339bb9 #22697d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
+.btn{cursor:pointer;display:inline-block;background-color:#e6e6e6;background-repeat:no-repeat;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);padding:5px 14px 6px;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);color:#333;font-size:13px;line-height:normal;border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-webkit-transform-style:preserve-3d;-webkit-transition:0.1s linear all;-moz-transition:0.1s linear all;-ms-transition:0.1s linear all;-o-transition:0.1s linear all;transition:0.1s linear all;}.btn:hover{background-position:0 -15px;color:#333;text-decoration:none;}
+.btn:focus{outline:1px dotted #666;}
+.btn.primary{color:#ffffff;background-color:#0064cd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));background-image:-moz-linear-gradient(top, #049cdb, #0064cd);background-image:-ms-linear-gradient(top, #049cdb, #0064cd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));background-image:-webkit-linear-gradient(top, #049cdb, #0064cd);background-image:-o-linear-gradient(top, #049cdb, #0064cd);background-image:linear-gradient(top, #049cdb, #0064cd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#0064cd #0064cd #003f81;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
+.btn.active,.btn :active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);}
+.btn.disabled{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+.btn[disabled]{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+.btn.large{font-size:15px;line-height:normal;padding:9px 14px 9px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
+.btn.small{padding:7px 9px 7px;font-size:11px;}
+:root .alert-message,:root .btn{border-radius:0 \0;}
+button.btn::-moz-focus-inner,input[type=submit].btn::-moz-focus-inner{padding:0;border:0;}
+.close{float:right;color:#000000;font-size:20px;font-weight:bold;line-height:13.5px;text-shadow:0 1px 0 #ffffff;filter:alpha(opacity=25);-khtml-opacity:0.25;-moz-opacity:0.25;opacity:0.25;}.close:hover{color:#000000;text-decoration:none;filter:alpha(opacity=40);-khtml-opacity:0.4;-moz-opacity:0.4;opacity:0.4;}
+.alert-message{position:relative;padding:7px 15px;margin-bottom:18px;color:#404040;background-color:#eedc94;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94));background-image:-moz-linear-gradient(top, #fceec1, #eedc94);background-image:-ms-linear-gradient(top, #fceec1, #eedc94);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94));background-image:-webkit-linear-gradient(top, #fceec1, #eedc94);background-image:-o-linear-gradient(top, #fceec1, #eedc94);background-image:linear-gradient(top, #fceec1, #eedc94);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#eedc94 #eedc94 #e4c652;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);border-width:1px;border-style:solid;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);}.alert-message .close{margin-top:1px;*margin-top:0;}
+.alert-message a{font-weight:bold;color:#404040;}
+.alert-message.danger p a,.alert-message.error p a,.alert-message.success p a,.alert-message.info p a{color:#ffffff;}
+.alert-message h5{line-height:18px;}
+.alert-message p{margin-bottom:0;}
+.alert-message div{margin-top:5px;margin-bottom:2px;line-height:28px;}
+.alert-message .btn{-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);box-shadow:0 1px 0 rgba(255, 255, 255, 0.25);}
+.alert-message.block-message{background-image:none;background-color:#fdf5d9;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);padding:14px;border-color:#fceec1;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}.alert-message.block-message ul,.alert-message.block-message p{margin-right:30px;}
+.alert-message.block-message ul{margin-bottom:0;}
+.alert-message.block-message li{color:#404040;}
+.alert-message.block-message .alert-actions{margin-top:5px;}
+.alert-message.block-message.error,.alert-message.block-message.success,.alert-message.block-message.info{color:#404040;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
+.alert-message.block-message.error{background-color:#fddfde;border-color:#fbc7c6;}
+.alert-message.block-message.success{background-color:#d1eed1;border-color:#bfe7bf;}
+.alert-message.block-message.info{background-color:#ddf4fb;border-color:#c6edf9;}
+.alert-message.block-message.danger p a,.alert-message.block-message.error p a,.alert-message.block-message.success p a,.alert-message.block-message.info p a{color:#404040;}
+.pagination{height:36px;margin:18px 0;}.pagination ul{float:left;margin:0;border:1px solid #ddd;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
+.pagination li{display:inline;}
+.pagination a{float:left;padding:0 14px;line-height:34px;border-right:1px solid;border-right-color:#ddd;border-right-color:rgba(0, 0, 0, 0.15);*border-right-color:#ddd;text-decoration:none;}
+.pagination a:hover,.pagination .active a{background-color:#c7eefe;}
+.pagination .disabled a,.pagination .disabled a:hover{background-color:transparent;color:#bfbfbf;}
+.pagination .next a{border:0;}
+.well{background-color:#f5f5f5;margin-bottom:20px;padding:19px;min-height:20px;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
+.modal-backdrop{background-color:#000000;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000;}.modal-backdrop.fade{opacity:0;}
+.modal-backdrop,.modal-backdrop.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}
+.modal{position:fixed;top:50%;left:50%;z-index:11000;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal .close{margin-top:7px;}
+.modal.fade{-webkit-transform-style:preserve-3d;-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
+.modal.fade.in{top:50%;}
+.modal-header{border-bottom:1px solid #eee;padding:5px 15px;}
+.modal-body{padding:15px;}
+.modal-body form{margin-bottom:0;}
+.modal-footer{background-color:#f5f5f5;padding:14px 15px 15px;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;zoom:1;margin-bottom:0;}.modal-footer:before,.modal-footer:after{display:table;content:"";zoom:1;}
+.modal-footer:after{clear:both;}
+.modal-footer .btn{float:right;margin-left:5px;}
+.modal .popover,.modal .twipsy{z-index:12000;}
+.twipsy{display:block;position:absolute;visibility:visible;padding:5px;font-size:11px;z-index:1000;filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}.twipsy.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}
+.twipsy.above .twipsy-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
+.twipsy.left .twipsy-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
+.twipsy.below .twipsy-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
+.twipsy.right .twipsy-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
+.twipsy-inner{padding:3px 8px;background-color:#000000;color:white;text-align:center;max-width:200px;text-decoration:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.twipsy-arrow{position:absolute;width:0;height:0;}
+.popover{position:absolute;top:0;left:0;z-index:1000;padding:5px;display:none;}.popover.above .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
+.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
+.popover.below .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
+.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
+.popover .arrow{position:absolute;width:0;height:0;}
+.popover .inner{background:#000000;background:rgba(0, 0, 0, 0.8);padding:3px;overflow:hidden;width:280px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);}
+.popover .title{background-color:#f5f5f5;padding:9px 15px;line-height:1;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;border-bottom:1px solid #eee;}
+.popover .content{background-color:#ffffff;padding:14px;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover .content p,.popover .content ul,.popover .content ol{margin-bottom:0;}
+.fade{-webkit-transform-style:preserve-3d;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;}
+.label{padding:1px 3px 2px;font-size:9.75px;font-weight:bold;color:#ffffff;text-transform:uppercase;white-space:nowrap;background-color:#bfbfbf;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}.label.important{background-color:#c43c35;}
+.label.warning{background-color:#f89406;}
+.label.success{background-color:#46a546;}
+.label.notice{background-color:#62cffc;}
+.media-grid{margin-left:-20px;margin-bottom:0;zoom:1;}.media-grid:before,.media-grid:after{display:table;content:"";zoom:1;}
+.media-grid:after{clear:both;}
+.media-grid li{display:inline;}
+.media-grid a{float:left;padding:4px;margin:0 0 18px 20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}.media-grid a img{display:block;}
+.media-grid a:hover{border-color:#0069d6;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}
diff --git a/doc/css/killbill.css b/doc/css/killbill.css
new file mode 100644
index 0000000..cf8ccee
--- /dev/null
+++ b/doc/css/killbill.css
@@ -0,0 +1,3 @@
+body {
+    padding-top: 60px;
+}
\ No newline at end of file

doc/css/prettify.css 118(+118 -0)

diff --git a/doc/css/prettify.css b/doc/css/prettify.css
new file mode 100644
index 0000000..3b38616
--- /dev/null
+++ b/doc/css/prettify.css
@@ -0,0 +1,118 @@
+
+/*
+ * Derived from einaros's Sons of Obsidian theme at
+ * http://studiostyl.es/schemes/son-of-obsidian by
+ * Alex Ford of CodeTunnel:
+ * http://CodeTunnel.com/blog/post/71/google-code-prettify-obsidian-theme
+ */
+
+.str
+{
+    color: #EC7600;
+}
+.kwd
+{
+    color: #93C763;
+}
+.com
+{
+    color: #66747B;
+}
+.typ
+{
+    color: #678CB1;
+}
+.lit
+{
+    color: #FACD22;
+}
+.pun
+{
+    color: #F1F2F3;
+}
+.pln
+{
+    color: #F1F2F3;
+}
+.tag
+{
+    color: #8AC763;
+}
+.atn
+{
+    color: #E0E2E4;
+}
+.atv
+{
+    color: #EC7600;
+}
+.dec
+{
+    color: purple;
+}
+pre.prettyprint
+{
+    border: 0px solid #888;
+}
+ol.linenums
+{
+    margin-top: 0;
+    margin-bottom: 0;
+}
+.prettyprint {
+    background: #000;
+}
+li.L0, li.L1, li.L2, li.L3, li.L4, li.L5, li.L6, li.L7, li.L8, li.L9
+{
+    color: #555;
+}
+li.L1, li.L3, li.L5, li.L7, li.L9 {
+    background: #111;
+}
+@media print
+{
+    .str
+    {
+        color: #060;
+    }
+    .kwd
+    {
+        color: #006;
+        font-weight: bold;
+    }
+    .com
+    {
+        color: #600;
+        font-style: italic;
+    }
+    .typ
+    {
+        color: #404;
+        font-weight: bold;
+    }
+    .lit
+    {
+        color: #044;
+    }
+    .pun
+    {
+        color: #440;
+    }
+    .pln
+    {
+        color: #000;
+    }
+    .tag
+    {
+        color: #006;
+        font-weight: bold;
+    }
+    .atn
+    {
+        color: #404;
+    }
+    .atv
+    {
+        color: #060;
+    }
+}
\ No newline at end of file

doc/design.html 100(+100 -0)

diff --git a/doc/design.html b/doc/design.html
new file mode 100644
index 0000000..0ff23be
--- /dev/null
+++ b/doc/design.html
@@ -0,0 +1,100 @@
+<!-- ~ Copyright 2010-2011 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. -->
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>Collector core | Dwarf</title>
+    <meta name="user guide" content="">
+    <meta name="author" content="Stephane Brossier">
+
+    <!--[if lt IE 9]>
+    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
+    <![endif]-->
+
+    <link rel=stylesheet type="text/css" href="css/bootstrap.min.css">
+    <link rel=stylesheet type="text/css" href="css/prettify.css">
+    <link rel=stylesheet type="text/css" href="css/killbill.css">
+    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+    <script src="js/prettify.js"></script>
+    <script src="js/bootstrap-dropdown.js"></script>
+
+    <script type="text/javascript">
+      var _gaq = _gaq || [];
+      _gaq.push(['_setAccount', 'UA-19297396-1']);
+      _gaq.push(['_trackPageview']);
+      (function() {
+        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+      })();
+    </script>
+</head>
+
+<body onload="prettyPrint();">
+
+    <div class="topbar" data-dropdown="dropdown">
+        <div class="topbar-inner">
+            <div class="container-fluid">
+                <a class="brand" href="../index.html">Killbill</a>
+                <ul class="nav">
+                    <li><a href="user.html">User Guide</a></li>
+                    <li><a href="setup.html">Setup/Installation</a></li>
+                    <li><a href="api.html">APIs</a></li>
+                    <li class="active"><a href="user.html">Setup/Installation</a></li>
+                    <li><a href="http://groups.google.com/group/killbill-users">Mailing List</a></li>
+                </ul>
+                <ul class="nav secondary-nav">
+                    <li class="dropdown">
+                        <a href="#" class="dropdown-toggle">Maven sites</a>
+                        <ul class="dropdown-menu">
+                            <li><a href="http://sbrossie.github.com/killbill" target="_blank">Killbill</a></li>
+                        </ul>
+                    </li>
+                </ul>
+                <ul class="nav secondary-nav">
+                    <li class="dropdown">
+                        <a href="#" class="dropdown-toggle">Github projects</a>
+                        <ul class="dropdown-menu">
+                            <li><a href="http://github.com/ning/killbill" target="_blank">Killbill</a></li>
+                        </ul>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+    <div class="container-fluid">
+        <div class="sidebar">
+            <div class="well">
+                <h5>Setup</h5>
+                <ul>
+                    <li><a href="#modularity">Modularity</a></li>                    
+                    <li><a href="#big-picture">Big Picture</a></li>
+                    <li><a href="#lifecycle">Lifecycle</a></li>
+                    <li><a href="#event-bus">Event Bus</a></li>                    
+                    <li><a href="#entitlement">Entitlement</a></li>
+                </ul>
+            </div>
+        </div>
+        <div class="content">
+            <h2 class="modularity">Modularity</h2>
+                Bla bla 
+            <h2 class="big-picture">Big Picture</h2>
+                Bla bla  
+            <h2 class="lifecycle">Lifecycle</h2>
+                Bla bla 
+            <h2 class="event-bus">Event Bus</h2>
+                Bla bla  
+            <h2 class="entitlement">Entitlement</h2>
+                Bla bla  
+        </div>
+    </div>
+</body>
+ 
diff --git a/doc/js/bootstrap-dropdown.js b/doc/js/bootstrap-dropdown.js
new file mode 100644
index 0000000..fda6da5
--- /dev/null
+++ b/doc/js/bootstrap-dropdown.js
@@ -0,0 +1,55 @@
+/* ============================================================
+ * bootstrap-dropdown.js v1.4.0
+ * http://twitter.github.com/bootstrap/javascript.html#dropdown
+ * ============================================================
+ * Copyright 2011 Twitter, Inc.
+ *
+ * Licensed 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.
+ * ============================================================ */
+
+
+!function( $ ){
+
+  "use strict"
+
+  /* DROPDOWN PLUGIN DEFINITION
+   * ========================== */
+
+  $.fn.dropdown = function ( selector ) {
+    return this.each(function () {
+      $(this).delegate(selector || d, 'click', function (e) {
+        var li = $(this).parent('li')
+          , isActive = li.hasClass('open')
+
+        clearMenus()
+        !isActive && li.toggleClass('open')
+        return false
+      })
+    })
+  }
+
+  /* APPLY TO STANDARD DROPDOWN ELEMENTS
+   * =================================== */
+
+  var d = 'a.menu, .dropdown-toggle'
+
+  function clearMenus() {
+    $(d).parent('li').removeClass('open')
+  }
+
+  $(function () {
+    $('html').bind("click", clearMenus)
+    $('body').dropdown( '[data-dropdown] a.menu, [data-dropdown] .dropdown-toggle' )
+  })
+
+}( window.jQuery || window.ender );

doc/js/prettify.js 28(+28 -0)

diff --git a/doc/js/prettify.js b/doc/js/prettify.js
new file mode 100644
index 0000000..eef5ad7
--- /dev/null
+++ b/doc/js/prettify.js
@@ -0,0 +1,28 @@
+var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
+(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
+[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
+f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
+(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
+{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
+t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
+"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
+l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
+q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
+q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
+"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
+a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
+for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
+m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
+a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
+j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
+H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
+J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
+I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
+["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
+/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
+["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
+hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
+!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
+250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
+PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();

doc/setup.html 97(+97 -0)

diff --git a/doc/setup.html b/doc/setup.html
new file mode 100644
index 0000000..02190dd
--- /dev/null
+++ b/doc/setup.html
@@ -0,0 +1,97 @@
+<!-- ~ Copyright 2010-2011 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. -->
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>Collector core | Dwarf</title>
+    <meta name="user guide" content="">
+    <meta name="author" content="Stephane Brossier">
+
+    <!--[if lt IE 9]>
+    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
+    <![endif]-->
+
+    <link rel=stylesheet type="text/css" href="css/bootstrap.min.css">
+    <link rel=stylesheet type="text/css" href="css/prettify.css">
+    <link rel=stylesheet type="text/css" href="css/killbill.css">
+    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+    <script src="js/prettify.js"></script>
+    <script src="js/bootstrap-dropdown.js"></script>
+
+    <script type="text/javascript">
+      var _gaq = _gaq || [];
+      _gaq.push(['_setAccount', 'UA-19297396-1']);
+      _gaq.push(['_trackPageview']);
+      (function() {
+        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+      })();
+    </script>
+</head>
+
+<body onload="prettyPrint();">
+
+    <div class="topbar" data-dropdown="dropdown">
+        <div class="topbar-inner">
+            <div class="container-fluid">
+                <a class="brand" href="../index.html">Killbill</a>
+                <ul class="nav">
+                    <li><a href="user.html">User Guide</a></li>
+                    <li class="active"><a href="user.html">Setup/Installation</a></li>
+                    <li><a href="api.html">APIs</a></li>
+                    <li><a href="design.html">Design</a></li>                                                
+                    <li><a href="http://groups.google.com/group/killbill-users">Mailing List</a></li>
+                </ul>
+                <ul class="nav secondary-nav">
+                    <li class="dropdown">
+                        <a href="#" class="dropdown-toggle">Maven sites</a>
+                        <ul class="dropdown-menu">
+                            <li><a href="http://sbrossie.github.com/killbill" target="_blank">Killbill</a></li>
+                        </ul>
+                    </li>
+                </ul>
+                <ul class="nav secondary-nav">
+                    <li class="dropdown">
+                        <a href="#" class="dropdown-toggle">Github projects</a>
+                        <ul class="dropdown-menu">
+                            <li><a href="http://github.com/ning/killbill" target="_blank">Killbill</a></li>
+                        </ul>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+    <div class="container-fluid">
+        <div class="sidebar">
+            <div class="well">
+                <h5>Setup</h5>
+                <ul>
+                    <li><a href="#prerequisite">Prerequisite</a></li>
+                    <li><a href="#install">Installation</a></li>
+                    <li><a href="#configuration">Configuration</a></li>
+                    <li><a href="#demo">Demo</a></li>                    
+                </ul>
+            </div>
+        </div>
+        <div class="content">
+            <h2 class="prerequisite">Prerequisite</h2>
+                Bla bla get me prerequisite
+            <h2 class="install">Installation</h2>
+                    install   
+            <h2 class="configuration">Configuration</h2>
+                    Configuration  
+            <h2 class="demo">Demo</h2>
+                   Demo
+        </div>
+    </div>
+</body>
+ 

doc/user.html 102(+102 -0)

diff --git a/doc/user.html b/doc/user.html
new file mode 100644
index 0000000..774fa84
--- /dev/null
+++ b/doc/user.html
@@ -0,0 +1,102 @@
+<!-- ~ Copyright 2010-2011 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. -->
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>Collector core | Dwarf</title>
+    <meta name="user guide" content="">
+    <meta name="author" content="Stephane Brossier">
+
+    <!--[if lt IE 9]>
+    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
+    <![endif]-->
+
+    <link rel=stylesheet type="text/css" href="css/bootstrap.min.css">
+    <link rel=stylesheet type="text/css" href="css/prettify.css">
+    <link rel=stylesheet type="text/css" href="css/killbill.css">
+    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+    <script src="js/prettify.js"></script>
+    <script src="js/bootstrap-dropdown.js"></script>
+
+    <script type="text/javascript">
+      var _gaq = _gaq || [];
+      _gaq.push(['_setAccount', 'UA-19297396-1']);
+      _gaq.push(['_trackPageview']);
+      (function() {
+        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+      })();
+    </script>
+</head>
+
+<body onload="prettyPrint();">
+
+    <div class="topbar" data-dropdown="dropdown">
+        <div class="topbar-inner">
+            <div class="container-fluid">
+                <a class="brand" href="../index.html">Killbill</a>
+                <ul class="nav">
+                    <li class="active"><a href="user.html">User Guide</a></li>
+                    <li><a href="setup.html">Setup/Installation</a></li>
+                    <li><a href="api.html">APIs</a></li>
+                    <li><a href="design.html">Design</a></li>                                                
+                    <li><a href="http://groups.google.com/group/killbill-users">Mailing List</a></li>
+                </ul>
+                <ul class="nav secondary-nav">
+                    <li class="dropdown">
+                        <a href="#" class="dropdown-toggle">Maven sites</a>
+                        <ul class="dropdown-menu">
+                            <li><a href="http://sbrossie.github.com/killbill" target="_blank">Killbill</a></li>
+                        </ul>
+                    </li>
+                </ul>
+                <ul class="nav secondary-nav">
+                    <li class="dropdown">
+                        <a href="#" class="dropdown-toggle">Github projects</a>
+                        <ul class="dropdown-menu">
+                            <li><a href="http://github.com/ning/killbill" target="_blank">Killbill</a></li>
+                        </ul>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+    
+    
+    <div class="container-fluid">
+        <div class="sidebar">
+            <div class="well">
+                <h5>User Guide</h5>
+                <ul>
+                    <li><a href="#getting-started">Getting Started</a></li>
+                    <li><a href="#catalog-configuration">Catalog Configuration</a></li>
+                    <li><a href="#automatic-billing">Automatic Billing</a></li>
+                    <li><a href="#proration">Proration</a></li>                    
+                    <li><a href="#payment-pluggin">Admin UI</a></li>                    
+                </ul>
+            </div>
+        </div>
+        <div class="content">
+            <h2 class="getting-started">Getting Started</h2>
+                Bla bla get me started    
+            <h2 class="catalog-configuration">Catalog Configuration</h2>
+                    Bla bla catalog config   
+            <h2 class="automatic-billing">Automatic Billing</h2>
+                    Automatic billing   
+            <h2 class="proration">Proration Logic</h2>
+                    Bla bla proration   
+            <h2 class="payment-pluggin">Payment Pluggin</h2>
+                   Bla bla payment plugin
+        </div>
+    </div>
+</body>
+ 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
index a55dcb7..5517eb8 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
@@ -21,7 +21,7 @@ import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.*;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.DefaultClock;
 import org.joda.time.DateTime;
@@ -119,7 +119,7 @@ public class PlanAligner  {
     public TimedPhase getNextTimedPhase(final SubscriptionData subscription, final DateTime requestedDate, final DateTime effectiveDate) {
         try {
 
-            SubscriptionTransition lastPlanTransition = subscription.getInitialTransitionForCurrentPlan();
+            SubscriptionEventTransition lastPlanTransition = subscription.getInitialTransitionForCurrentPlan();
             if (effectiveDate.isBefore(lastPlanTransition.getEffectiveTransitionTime())) {
                 throw new EntitlementError(String.format("Cannot specify an effectiveDate prior to last Plan Change, subscription = %s, effectiveDate = %s",
                         subscription.getId(), effectiveDate));
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java
index 92b6654..0fb0518 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java
@@ -35,8 +35,8 @@ import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 
 public class BillCycleDayCalculator {
 	private static final Logger log = LoggerFactory.getLogger(BillCycleDayCalculator.class);
@@ -51,7 +51,7 @@ public class BillCycleDayCalculator {
 		this.entitlementApi = entitlementApi;
 	}
 
-	protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionTransition transition, final Account account) throws CatalogApiException, AccountApiException {
+	protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionEventTransition transition, final Account account) throws CatalogApiException, AccountApiException {
 		Catalog catalog = catalogService.getFullCatalog();
 		Plan plan =  (transition.getTransitionType() != SubscriptionTransitionType.CANCEL) ?
 				transition.getNextPlan() : transition.getPreviousPlan();
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
index b3ada17..646155b 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
@@ -27,8 +27,8 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 
 public class DefaultBillingEvent implements BillingEvent {
@@ -47,7 +47,7 @@ public class DefaultBillingEvent implements BillingEvent {
     final private SubscriptionTransitionType type;
     final private Long totalOrdering;
 
-    public DefaultBillingEvent(Account account, SubscriptionTransition transition, Subscription subscription, int billCycleDay, Currency currency) throws CatalogApiException {
+    public DefaultBillingEvent(Account account, SubscriptionEventTransition transition, Subscription subscription, int billCycleDay, Currency currency) throws CatalogApiException {
         this.account = account;
         this.billCycleDay = billCycleDay;
         this.subscription = subscription;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
index 7af5e5c..b73de3b 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
@@ -22,15 +22,6 @@ import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.UUID;
 
-
-import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.CallContextFactory;
-
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.slf4j.Logger;
@@ -44,11 +35,13 @@ import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.engine.dao.SubscriptionSqlDao;
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.audit.dao.AuditSqlDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;
 import com.ning.billing.util.callcontext.CallOrigin;
@@ -87,7 +80,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         	List<Subscription> subscriptions = entitlementDao.getSubscriptions(subscriptionFactory, bundle.getId());
 
         	for (final Subscription subscription: subscriptions) {
-        		for (final SubscriptionTransition transition : ((SubscriptionData) subscription).getBillingTransitions()) {
+        		for (final SubscriptionEventTransition transition : ((SubscriptionData) subscription).getBillingTransitions()) {
         			try {
         			    int bcd = bcdCalculator.calculateBcd(bundle, subscription, transition, account);
         			    
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
index d0fb35b..8390504 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
@@ -72,11 +72,11 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
     @Override
     public void migrate(EntitlementAccountMigration toBeMigrated, CallContext context)
     throws EntitlementMigrationApiException {
-        AccountMigrationData accountMigrationData = createAccountMigrationData(toBeMigrated);
+        AccountMigrationData accountMigrationData = createAccountMigrationData(toBeMigrated, context);
         dao.migrate(toBeMigrated.getAccountKey(), accountMigrationData, context);
     }
 
-    private AccountMigrationData createAccountMigrationData(EntitlementAccountMigration toBeMigrated)
+    private AccountMigrationData createAccountMigrationData(EntitlementAccountMigration toBeMigrated, CallContext context)
     throws EntitlementMigrationApiException  {
 
         final UUID accountId = toBeMigrated.getAccountKey();
@@ -118,10 +118,11 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
             for (EntitlementSubscriptionMigration curSub : sortedSubscriptions) {
                 SubscriptionMigrationData data = null;
                 if (bundleStartDate == null) {
-                    data = createInitialSubscription(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now, curSub.getChargedThroughDate());
+                    data = createInitialSubscription(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now, curSub.getChargedThroughDate(), context);
                     bundleStartDate = data.getInitialEvents().get(0).getEffectiveDate();
                 } else {
-                    data = createSubscriptionMigrationDataWithBundleDate(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now, bundleStartDate, curSub.getChargedThroughDate());
+                    data = createSubscriptionMigrationDataWithBundleDate(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now,
+                    		bundleStartDate, curSub.getChargedThroughDate(), context);
                 }
                 if (data != null) {
                     bundleSubscriptionData.add(data);
@@ -135,7 +136,7 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
     }
 
     private SubscriptionMigrationData createInitialSubscription(UUID bundleId, ProductCategory productCategory,
-            EntitlementSubscriptionMigrationCase [] input, DateTime now, DateTime ctd)
+            EntitlementSubscriptionMigrationCase [] input, DateTime now, DateTime ctd, CallContext context)
         throws EntitlementMigrationApiException {
 
         TimedMigration [] events = migrationAligner.getEventsMigration(input, now);
@@ -148,11 +149,11 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
             .setBundleStartDate(migrationStartDate)
             .setStartDate(migrationStartDate),
             emptyEvents);
-        return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, ctd, events));
+        return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, ctd, events, context));
     }
 
     private SubscriptionMigrationData createSubscriptionMigrationDataWithBundleDate(UUID bundleId, ProductCategory productCategory,
-            EntitlementSubscriptionMigrationCase [] input, DateTime now, DateTime bundleStartDate, DateTime ctd)
+            EntitlementSubscriptionMigrationCase [] input, DateTime now, DateTime bundleStartDate, DateTime ctd, CallContext context)
     throws EntitlementMigrationApiException {
         TimedMigration [] events = migrationAligner.getEventsMigration(input, now);
         DateTime migrationStartDate= events[0].getEventTime();
@@ -164,10 +165,10 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
             .setBundleStartDate(bundleStartDate)
             .setStartDate(migrationStartDate),
             emptyEvents);
-        return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, ctd, events));
+        return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, ctd, events, context));
     }
 
-    private List<EntitlementEvent> toEvents(SubscriptionData subscriptionData, DateTime now, DateTime ctd, TimedMigration [] migrationEvents) {
+    private List<EntitlementEvent> toEvents(SubscriptionData subscriptionData, DateTime now, DateTime ctd, TimedMigration [] migrationEvents, CallContext context) {
 
 
         ApiEventMigrateEntitlement creationEvent = null;
@@ -189,6 +190,7 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
                 .setEffectiveDate(cur.getEventTime())
                 .setProcessedDate(now)
                 .setRequestedDate(now)
+                .setUserToken(context.getUserToken())
                 .setFromDisk(true);
 
                 switch(cur.getApiEventType()) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
index 7fc99a2..59040be 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
@@ -31,7 +31,6 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.Product;
-import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
@@ -46,20 +45,18 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
     private final EntitlementDao dao;
     private final CatalogService catalogService;
     private final SubscriptionApiService apiService;
-    private final OverdueChecker overdueChecker;
     private final AddonUtils addonUtils;
     private final SubscriptionFactory subscriptionFactory;
 
     @Inject
     public DefaultEntitlementUserApi(Clock clock, EntitlementDao dao, CatalogService catalogService,
-            SubscriptionApiService apiService, final SubscriptionFactory subscriptionFactory, AddonUtils addonUtils, OverdueChecker overdueChecker) {
+            SubscriptionApiService apiService, final SubscriptionFactory subscriptionFactory, AddonUtils addonUtils) {
         super();
         this.clock = clock;
         this.apiService = apiService;
         this.dao = dao;
         this.catalogService = catalogService;
         this.addonUtils = addonUtils;
-        this.overdueChecker = overdueChecker;
         this.subscriptionFactory = subscriptionFactory;
     }
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
index 2a69428..563cc80 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
@@ -38,7 +38,6 @@ import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.alignment.PlanAligner;
 import com.ning.billing.entitlement.alignment.TimedPhase;
-import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
@@ -63,35 +62,30 @@ public class SubscriptionApiService {
     private final EntitlementDao dao;
     private final CatalogService catalogService;
     private final PlanAligner planAligner;
-    private final OverdueChecker overdueChecker;
 
     @Inject
-    public SubscriptionApiService(Clock clock, EntitlementDao dao, CatalogService catalogService, PlanAligner planAligner, OverdueChecker overdueChecker) {
+    public SubscriptionApiService(Clock clock, EntitlementDao dao, CatalogService catalogService, PlanAligner planAligner) {
         this.clock = clock;
         this.catalogService = catalogService;
         this.planAligner = planAligner;
         this.dao = dao;
-        this.overdueChecker = overdueChecker;
     }
 
     public SubscriptionData createPlan(SubscriptionBuilder builder, Plan plan, PhaseType initialPhase,
             String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate,
             CallContext context)
         throws EntitlementUserApiException {
-        
         SubscriptionData subscription = new SubscriptionData(builder, this, clock);
 
-        overdueChecker.checkBlocked(subscription);
 
         
         createFromSubscription(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, false, context);
         return subscription;
     }
 
-    public void recreatePlan(SubscriptionData subscription, PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
-        throws EntitlementUserApiException {
-        
-        overdueChecker.checkBlocked(subscription);
+
+    public boolean recreatePlan(SubscriptionData subscription, PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
+    throws EntitlementUserApiException {
 
         SubscriptionState currentState = subscription.getState();
         if (currentState != SubscriptionState.CANCELLED) {
@@ -114,6 +108,7 @@ public class SubscriptionApiService {
             DateTime processedDate = now;
 
             createFromSubscription(subscription, plan, spec.getPhaseType(), realPriceList, requestedDate, effectiveDate, processedDate, true, context);
+            return true;
         } catch (CatalogApiException e) {
             throw new EntitlementUserApiException(e);
         }
@@ -122,9 +117,8 @@ public class SubscriptionApiService {
     private void createFromSubscription(SubscriptionData subscription, Plan plan, PhaseType initialPhase,
             String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate,
             boolean reCreate, CallContext context)
-        throws EntitlementUserApiException {
+    throws EntitlementUserApiException {
 
-        overdueChecker.checkBlocked(subscription);
 
         try {
             TimedPhase [] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate);
@@ -138,6 +132,7 @@ public class SubscriptionApiService {
             .setProcessedDate(processedDate)
             .setEffectiveDate(effectiveDate)
             .setRequestedDate(requestedDate)
+            .setUserToken(context.getUserToken())            
             .setFromDisk(true);
             ApiEvent creationEvent = (reCreate) ? new ApiEventReCreate(createBuilder) : new ApiEventCreate(createBuilder);
 
@@ -145,24 +140,24 @@ public class SubscriptionApiService {
             PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                     PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, processedDate, nextTimedPhase.getStartPhase()) :
                         null;
-            List<EntitlementEvent> events = new ArrayList<EntitlementEvent>();
-            events.add(creationEvent);
-            if (nextPhaseEvent != null) {
-                events.add(nextPhaseEvent);
-            }
-            if (reCreate) {
-                dao.recreateSubscription(subscription.getId(), events, context);
-            } else {
-                dao.createSubscription(subscription, events, context);
-            }
-            subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
+                    List<EntitlementEvent> events = new ArrayList<EntitlementEvent>();
+                    events.add(creationEvent);
+                    if (nextPhaseEvent != null) {
+                        events.add(nextPhaseEvent);
+                    }
+                    if (reCreate) {
+                        dao.recreateSubscription(subscription.getId(), events, context);
+                    } else {
+                        dao.createSubscription(subscription, events, context);
+                    }
+                    subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
         } catch (CatalogApiException e) {
             throw new EntitlementUserApiException(e);
         }
     }
 
-    public void cancel(SubscriptionData subscription, DateTime requestedDate, boolean eot, CallContext context)
-        throws EntitlementUserApiException {
+    public boolean cancel(SubscriptionData subscription, DateTime requestedDate, boolean eot, CallContext context)
+    throws EntitlementUserApiException {
 
         try {
             SubscriptionState currentState = subscription.getState();
@@ -181,8 +176,7 @@ public class SubscriptionApiService {
                     subscription.getCurrentPriceList().getName(),
                     subscription.getCurrentPhase().getPhaseType());
 
-            ActionPolicy policy = null;
-            policy = catalogService.getFullCatalog().planCancelPolicy(planPhase, requestedDate);
+            ActionPolicy policy = catalogService.getFullCatalog().planCancelPolicy(planPhase, requestedDate);
             DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, requestedDate);
 
             EntitlementEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
@@ -191,18 +185,20 @@ public class SubscriptionApiService {
             .setProcessedDate(now)
             .setEffectiveDate(effectiveDate)
             .setRequestedDate(requestedDate)
+            .setUserToken(context.getUserToken())
             .setFromDisk(true));
 
-            dao.cancelSubscription(subscription.getId(), cancelEvent, context);
+            dao.cancelSubscription(subscription.getId(), cancelEvent, context, 0);
             subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
+            return (policy == ActionPolicy.IMMEDIATE);
         } catch (CatalogApiException e) {
             throw new EntitlementUserApiException(e);
         }
     }
 
 
-    public void uncancel(SubscriptionData subscription, CallContext context)
-        throws EntitlementUserApiException {
+    public boolean uncancel(SubscriptionData subscription, CallContext context)
+    throws EntitlementUserApiException {
 
         if (!subscription.isSubscriptionFutureCancelled()) {
             throw new EntitlementUserApiException(ErrorCode.ENT_UNCANCEL_BAD_STATE, subscription.getId().toString());
@@ -215,6 +211,7 @@ public class SubscriptionApiService {
         .setProcessedDate(now)
         .setRequestedDate(now)
         .setEffectiveDate(now)
+        .setUserToken(context.getUserToken())
         .setFromDisk(true));
 
         List<EntitlementEvent> uncancelEvents = new ArrayList<EntitlementEvent>();
@@ -224,18 +221,18 @@ public class SubscriptionApiService {
         PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                 PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, now, nextTimedPhase.getStartPhase()) :
                     null;
-        if (nextPhaseEvent != null) {
-            uncancelEvents.add(nextPhaseEvent);
-        }
-        dao.uncancelSubscription(subscription.getId(), uncancelEvents, context);
-        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
+                if (nextPhaseEvent != null) {
+                    uncancelEvents.add(nextPhaseEvent);
+                }
+                dao.uncancelSubscription(subscription.getId(), uncancelEvents, context);
+                subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
+                return true;
     }
 
-    public void changePlan(SubscriptionData subscription, String productName, BillingPeriod term,
+    public boolean changePlan(SubscriptionData subscription, String productName, BillingPeriod term,
             String priceList, DateTime requestedDate, CallContext context)
-        throws EntitlementUserApiException {
-        
-        overdueChecker.checkBlocked(subscription);
+
+    throws EntitlementUserApiException {
 
         try {
 
@@ -289,20 +286,22 @@ public class SubscriptionApiService {
             .setProcessedDate(now)
             .setEffectiveDate(effectiveDate)
             .setRequestedDate(requestedDate)
+            .setUserToken(context.getUserToken())            
             .setFromDisk(true));
 
             TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, newPriceList.getName(), requestedDate, effectiveDate);
             PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                     PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, now, nextTimedPhase.getStartPhase()) :
                         null;
-                    List<EntitlementEvent> changeEvents = new ArrayList<EntitlementEvent>();
-                    // Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.
-                    if (nextPhaseEvent != null && ! nextPhaseEvent.getEffectiveDate().equals(changeEvent.getEffectiveDate())) {
-                        changeEvents.add(nextPhaseEvent);
-                    }
-                    changeEvents.add(changeEvent);
-                    dao.changePlan(subscription.getId(), changeEvents, context);
-                    subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
+            List<EntitlementEvent> changeEvents = new ArrayList<EntitlementEvent>();
+            // Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.
+            if (nextPhaseEvent != null && ! nextPhaseEvent.getEffectiveDate().equals(changeEvent.getEffectiveDate())) {
+                changeEvents.add(nextPhaseEvent);
+            }
+            changeEvents.add(changeEvent);
+            dao.changePlan(subscription.getId(), changeEvents, context);
+            subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
+            return (policy == ActionPolicy.IMMEDIATE);
         } catch (CatalogApiException e) {
             throw new EntitlementUserApiException(e);
         }
@@ -320,7 +319,7 @@ public class SubscriptionApiService {
             throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_REQUESTED_FUTURE_DATE, requestedDate.toString());
         }
 
-        SubscriptionTransition previousTransition = subscription.getPreviousTransition();
+        SubscriptionEventTransition previousTransition = subscription.getPreviousTransition();
         if (previousTransition.getEffectiveTransitionTime().isAfter(requestedDate)) {
             throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_REQUESTED_DATE,
                     requestedDate.toString(), previousTransition.getEffectiveTransitionTime());
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java
index 38a6ff5..0fac2c8 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java
@@ -20,7 +20,7 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 
-import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.overdue.config.api.OverdueState;
 
 public class SubscriptionBundleData implements SubscriptionBundle {
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index a5b76ab..feae851 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -38,7 +38,7 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionDataIterator.Kind;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionDataIterator.Order;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionDataIterator.TimeLimit;
@@ -157,7 +157,7 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
 
     @Override
     public DateTime getEndDate() {
-        SubscriptionTransition latestTransition = getPreviousTransition();
+        SubscriptionEventTransition latestTransition = getPreviousTransition();
         if (latestTransition.getNextState() == SubscriptionState.CANCELLED) {
             return latestTransition.getEffectiveTransitionTime();
         }
@@ -166,33 +166,33 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
 
 
     @Override
-    public void cancel(DateTime requestedDate, boolean eot, CallContext context) throws EntitlementUserApiException  {
-        apiService.cancel(this, requestedDate, eot, context);
+    public boolean cancel(DateTime requestedDate, boolean eot, CallContext context) throws EntitlementUserApiException  {
+        return apiService.cancel(this, requestedDate, eot, context);
     }
 
     @Override
-    public void uncancel(CallContext context) throws EntitlementUserApiException {
-        apiService.uncancel(this, context);
+    public boolean uncancel(CallContext context) throws EntitlementUserApiException {
+        return apiService.uncancel(this, context);
     }
 
     @Override
-    public void changePlan(String productName, BillingPeriod term,
+    public boolean changePlan(String productName, BillingPeriod term,
             String priceList, DateTime requestedDate, CallContext context) throws EntitlementUserApiException {
-        apiService.changePlan(this, productName, term, priceList, requestedDate, context);
+        return apiService.changePlan(this, productName, term, priceList, requestedDate, context);
     }
 
     @Override
-    public void recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
+    public boolean recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
             throws EntitlementUserApiException {
-        apiService.recreatePlan(this, spec, requestedDate, context);
+        return apiService.recreatePlan(this, spec, requestedDate, context);
     }
 
-    public List<SubscriptionTransition> getBillingTransitions() {
+    public List<SubscriptionEventTransition> getBillingTransitions() {
 
         if (transitions == null) {
             return Collections.emptyList();
         }
-        List<SubscriptionTransition> result = new ArrayList<SubscriptionTransition>();
+        List<SubscriptionEventTransition> result = new ArrayList<SubscriptionEventTransition>();
         SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions,
                 Order.ASC_FROM_PAST, Kind.BILLING, Visibility.ALL, TimeLimit.ALL);
         while (it.hasNext()) {
@@ -202,7 +202,7 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
     }
 
     @Override
-    public SubscriptionTransition getPendingTransition() {
+    public SubscriptionEventTransition getPendingTransition() {
 
         if (transitions == null) {
             return null;
@@ -213,7 +213,7 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
     }
 
     @Override
-    public SubscriptionTransition getPreviousTransition() {
+    public SubscriptionEventTransition getPreviousTransition() {
         if (transitions == null) {
             return null;
         }
@@ -222,13 +222,13 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
         return it.hasNext() ? it.next() : null;
     }
 
-    public SubscriptionTransition getTransitionFromEvent(EntitlementEvent event) {
+    public SubscriptionEventTransition getTransitionFromEvent(final EntitlementEvent event, final int seqId) {
         if (transitions == null || event == null) {
             return null;
         }
-        for (SubscriptionTransition cur : transitions) {
+        for (SubscriptionEventTransition cur : transitions) {
             if (cur.getId().equals(event.getId())) {
-                return cur;
+                return new SubscriptionTransitionData((SubscriptionTransitionData) cur, seqId);
             }
         }
         return null;
@@ -339,6 +339,7 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
         String nextPlanName = null;
         String nextPhaseName = null;
         String nextPriceListName = null; 
+        UUID nextUserToken = null;
         
         SubscriptionState previousState = null;
         PriceList previousPriceList = null;
@@ -368,6 +369,8 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
                 ApiEvent userEV = (ApiEvent) cur;
                 apiEventType = userEV.getEventType();
                 isFromDisk = userEV.isFromDisk();
+                nextUserToken = userEV.getUserToken();
+                
                 switch(apiEventType) {
                 case MIGRATE_BILLING:
                 case MIGRATE_ENTITLEMENT:
@@ -433,7 +436,9 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
                         nextPhase,
                         nextPriceList,
                         cur.getTotalOrdering(),
+                        nextUserToken,
                         isFromDisk);
+
             transitions.add(transition);
 
             previousState = nextState;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
index f420e98..3e52a2e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
@@ -28,7 +28,7 @@ import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 
-public class SubscriptionTransitionData implements SubscriptionTransition {
+public class SubscriptionTransitionData implements SubscriptionEventTransition {
 
 
     private final long totalOrdering;
@@ -48,12 +48,14 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
     private final Plan nextPlan;
     private final PlanPhase nextPhase;
     private final boolean isFromDisk;
+    private final int remainingEventsForUserOperation;
+    private final UUID userToken;
 
     public SubscriptionTransitionData(UUID eventId, UUID subscriptionId, UUID bundleId, EventType eventType,
             ApiEventType apiEventType, DateTime requestedTransitionTime, DateTime effectiveTransitionTime,
             SubscriptionState previousState, Plan previousPlan, PlanPhase previousPhase, PriceList previousPriceList,
             SubscriptionState nextState, Plan nextPlan, PlanPhase nextPhase, PriceList nextPriceList,
-            long totalOrdering, boolean isFromDisk) {
+            long totalOrdering, UUID userToken, boolean isFromDisk) {
         super();
         this.eventId = eventId;
         this.subscriptionId = subscriptionId;
@@ -72,7 +74,38 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
         this.nextPhase = nextPhase;
         this.totalOrdering = totalOrdering;
         this.isFromDisk = isFromDisk;
+        this.userToken = userToken;
+        this.remainingEventsForUserOperation = 0;
     }
+    
+    public SubscriptionTransitionData(final SubscriptionTransitionData input, final int remainingEventsForUserOperation) {
+        super();
+        this.eventId = input.getId();
+        this.subscriptionId = input.getSubscriptionId();
+        this.bundleId = input.getBundleId();
+        this.eventType = input.getEventType();
+        this.apiEventType = input.getApiEventType();
+        this.requestedTransitionTime = input.getRequestedTransitionTime();
+        this.effectiveTransitionTime = input.getEffectiveTransitionTime();
+        this.previousState = input.getPreviousState();
+        this.previousPriceList = input.getPreviousPriceList();
+        this.previousPlan = input.getPreviousPlan();
+        this.previousPhase = input.getPreviousPhase();
+        this.nextState = input.getNextState();
+        this.nextPlan = input.getNextPlan();
+        this.nextPriceList = input.getNextPriceList();
+        this.nextPhase = input.getNextPhase();
+        this.totalOrdering = input.getTotalOrdering();
+        this.isFromDisk = input.isFromDisk();
+        this.userToken = input.getUserToken();
+        this.remainingEventsForUserOperation = remainingEventsForUserOperation;
+    }
+
+	@Override
+	public BusEventType getBusEventType() {
+		return BusEventType.SUBSCRIPTION_TRANSITION;
+	}
+
 
     @Override
     public UUID getId() {
@@ -130,6 +163,17 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
     public PriceList getNextPriceList() {
         return nextPriceList;
     }
+    
+	@Override
+	public UUID getUserToken() {
+		return userToken;
+	}
+	
+	@Override
+	public Integer getRemainingEventsForUserOperation() {
+		return remainingEventsForUserOperation;
+	}
+
 
     @Override
     public SubscriptionTransitionType getTransitionType() {
@@ -187,5 +231,4 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
             + ", nextPriceList " + nextPriceList
             + ", nextPhase=" + ((nextPhase != null) ? nextPhase.getName() : null) + "]";
     }
-
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
index fbab9b2..3e5e961 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
@@ -19,7 +19,7 @@ package com.ning.billing.entitlement.api.user;
 import java.util.Iterator;
 import java.util.LinkedList;
 
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.Clock;
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
index b2c9405..e7c5139 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
@@ -29,7 +29,7 @@ import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 
 public class AddonUtils {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index 32ffb90..2984ac3 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -18,9 +18,13 @@ package com.ning.billing.entitlement.engine.core;
 
 
 
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 
 import com.ning.billing.util.callcontext.CallContext;
@@ -37,6 +41,7 @@ import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.config.EntitlementConfig;
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.entitlement.alignment.PlanAligner;
 import com.ning.billing.entitlement.alignment.TimedPhase;
 import com.ning.billing.entitlement.api.EntitlementService;
@@ -65,7 +70,6 @@ import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
-import com.ning.billing.util.notificationq.NotificationConfig;
 import com.ning.billing.util.notificationq.NotificationQueue;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
@@ -73,6 +77,7 @@ import com.ning.billing.util.notificationq.NotificationQueueService.Notification
 
 public class Engine implements EventListener, EntitlementService {
 
+	
     public static final String NOTIFICATION_QUEUE_NAME = "subscription-events";
     public static final String ENTITLEMENT_SERVICE_NAME = "entitlement-service";
 
@@ -129,20 +134,26 @@ public class Engine implements EventListener, EntitlementService {
                     NOTIFICATION_QUEUE_NAME,
                     new NotificationQueueHandler() {
                 @Override
-                public void handleReadyNotification(String notificationKey, DateTime eventDateTime) {
-                    EntitlementEvent event = dao.getEventById(UUID.fromString(notificationKey));
+                public void handleReadyNotification(final String inputKey, final DateTime eventDateTime) {
+                	
+                	EntitlementNotificationKey key = new EntitlementNotificationKey(inputKey);
+                    final EntitlementEvent event = dao.getEventById(key.getEventId());
                     if (event == null) {
-                        log.warn("Failed to extract event for notification key {}", notificationKey);
-                    } else {
-                        final CallContext context = factory.createCallContext("SubscriptionEventQueue", CallOrigin.INTERNAL, UserType.SYSTEM);
-                        processEventReady(event, context);
+                        log.warn("Failed to extract event for notification key {}", inputKey);
+                        return;
                     }
+                    final UUID userToken =  (event.getType() == EventType.API_USER) ? ((ApiEvent) event).getUserToken() : null;
+                    final CallContext context = factory.createCallContext("SubscriptionEventQueue", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
+                    processEventReady(event, key.getSeqId(), context);
                 }
+                
+    
+
             },
             new NotificationConfig() {
                 @Override
                 public boolean isNotificationProcessingOff() {
-                    return config.isEventProcessingOff();
+                    return config.isNotificationProcessingOff();
                 }
                 @Override
                 public long getNotificationSleepTimeMs() {
@@ -192,7 +203,7 @@ public class Engine implements EventListener, EntitlementService {
 
 
     @Override
-    public void processEventReady(EntitlementEvent event, CallContext context) {
+    public void processEventReady(final EntitlementEvent event, final int seqId, final CallContext context) {
         if (!event.isActive()) {
             return;
         }
@@ -204,14 +215,16 @@ public class Engine implements EventListener, EntitlementService {
         //
         // Do any internal processing on that event before we send the event to the bus
         //
+        
+        int theRealSeqId = seqId;
         if (event.getType() == EventType.PHASE) {
             onPhaseEvent(subscription, context);
         } else if (event.getType() == EventType.API_USER &&
                 subscription.getCategory() == ProductCategory.BASE) {
-            onBasePlanEvent(subscription, (ApiEvent) event, context);
+        	theRealSeqId = onBasePlanEvent(subscription, (ApiEvent) event, context);
         }
         try {
-            eventBus.post(subscription.getTransitionFromEvent(event));
+            eventBus.post(subscription.getTransitionFromEvent(event, theRealSeqId));
         } catch (EventBusException e) {
             log.warn("Failed to post entitlement event " + event, e);
         }
@@ -233,7 +246,7 @@ public class Engine implements EventListener, EntitlementService {
         }
     }
 
-    private void onBasePlanEvent(SubscriptionData baseSubscription, ApiEvent event, CallContext context) {
+    private int onBasePlanEvent(SubscriptionData baseSubscription, ApiEvent event, CallContext context) {
 
         DateTime now = clock.getUTCNow();
 
@@ -242,6 +255,9 @@ public class Engine implements EventListener, EntitlementService {
 
         List<Subscription> subscriptions = dao.getSubscriptions(subscriptionFactory, baseSubscription.getBundleId());
 
+        
+        Map<UUID, EntitlementEvent> addOnCancellations = new HashMap<UUID, EntitlementEvent>();
+        
         Iterator<Subscription> it = subscriptions.iterator();
         while (it.hasNext()) {
             SubscriptionData cur = (SubscriptionData) it.next();
@@ -262,9 +278,18 @@ public class Engine implements EventListener, EntitlementService {
                 .setProcessedDate(now)
                 .setEffectiveDate(event.getEffectiveDate())
                 .setRequestedDate(now)
+                .setUserToken(context.getUserToken())
                 .setFromDisk(true));
-                dao.cancelSubscription(cur.getId(), cancelEvent, context);
+                
+                addOnCancellations.put(cur.getId(), cancelEvent);
             }
         }
+        final int addOnSize = addOnCancellations.size();
+        int cancelSeq = addOnSize - 1;
+        for (final UUID key : addOnCancellations.keySet()) {
+            dao.cancelSubscription(key, addOnCancellations.get(key), context, cancelSeq);
+            cancelSeq--;
+        }
+        return addOnSize;
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementNotificationKey.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementNotificationKey.java
new file mode 100644
index 0000000..a4d19b0
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementNotificationKey.java
@@ -0,0 +1,91 @@
+/* 
+ * Copyright 2010-2011 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.entitlement.engine.core;
+
+import java.util.UUID;
+import com.ning.billing.util.notificationq.NotificationKey;
+
+public class EntitlementNotificationKey implements NotificationKey {
+
+	private static final String DELIMITER = ":";
+	
+	private final UUID eventId;
+	private final int seqId;
+	
+	public EntitlementNotificationKey(final UUID eventId, int seqId) {
+		this.eventId = eventId;
+		this.seqId = seqId;
+	}
+
+	public EntitlementNotificationKey(final UUID eventId) {
+		this(eventId, 0);
+	}
+	
+	public EntitlementNotificationKey(final String input) {
+			
+		String [] parts = input.split(DELIMITER);
+		eventId = UUID.fromString(parts[0]);
+		if (parts.length == 2) {
+			seqId = Integer.valueOf(parts[1]);
+		} else {
+			seqId = 0;
+		}
+	}
+	
+	public UUID getEventId() {
+		return eventId;
+	}
+
+	public int getSeqId() {
+		return seqId;
+	}
+
+	public String toString() {
+		if (seqId == 0) {
+			return eventId.toString();
+		} else {
+			return eventId.toString() + ":" + seqId;
+		}
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((eventId == null) ? 0 : eventId.hashCode());
+		result = prime * result + seqId;
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		EntitlementNotificationKey other = (EntitlementNotificationKey) obj;
+		if (eventId == null) {
+			if (other.eventId != null)
+				return false;
+		} else if (!eventId.equals(other.eventId))
+			return false;
+		if (seqId != other.seqId)
+			return false;
+		return true;
+	}
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventListener.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventListener.java
index f6b13f9..1272dba 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventListener.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventListener.java
@@ -22,6 +22,6 @@ import com.ning.billing.util.callcontext.CallContext;
 
 public interface EventListener {
 
-    public void processEventReady(EntitlementEvent event, CallContext context);
+    public void processEventReady(final EntitlementEvent event, final int seqId, final CallContext context);
 
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
index d79444a..4415c1d 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
@@ -68,8 +68,8 @@ public interface EntitlementDao {
 
     public void recreateSubscription(final UUID subscriptionId, final List<EntitlementEvent> recreateEvents, final CallContext context);
 
-    public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context);
-
+    public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context, final int cancelSeq);
+    
     public void uncancelSubscription(final UUID subscriptionId, final List<EntitlementEvent> uncancelEvents, final CallContext context);
 
     public void changePlan(final UUID subscriptionId, final List<EntitlementEvent> changeEvents, final CallContext context);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
index 12d5f15..89d2b1e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
@@ -38,11 +38,9 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.catalog.api.overdue.OverdueState;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData.BundleMigrationData;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData.SubscriptionMigrationData;
@@ -54,6 +52,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionFactory;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
 import com.ning.billing.entitlement.engine.core.Engine;
+import com.ning.billing.entitlement.engine.core.EntitlementNotificationKey;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.user.ApiEvent;
@@ -73,9 +72,9 @@ import com.ning.billing.util.notificationq.NotificationKey;
 import com.ning.billing.util.notificationq.NotificationQueue;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 import com.ning.billing.util.notificationq.NotificationQueueService.NoSuchNotificationQueue;
-import com.ning.billing.util.overdue.OverdueAccessApi;
 
 public class EntitlementSqlDao implements EntitlementDao {
+
     private final static Logger log = LoggerFactory.getLogger(EntitlementSqlDao.class);
     public static final String ENTITLEMENT_EVENTS_TABLE_NAME = "entitlement_events";
     public static final String BUNDLES_TABLE_NAME = "bundles";
@@ -88,7 +87,6 @@ public class EntitlementSqlDao implements EntitlementDao {
     private final NotificationQueueService notificationQueueService;
     private final AddonUtils addonUtils;
     private final CustomFieldDao customFieldDao;
-    private final OverdueAccessApi overdueApi;
     private final CatalogService catalogService;
 
     
@@ -102,7 +100,6 @@ public class EntitlementSqlDao implements EntitlementDao {
     public EntitlementSqlDao(final IDBI dbi, final Clock clock,
                              final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
                              final CustomFieldDao customFieldDao,
-                             final OverdueAccessApi overdueApi,
                              final CatalogService catalogService) {
         this.clock = clock;
         this.subscriptionsDao = dbi.onDemand(SubscriptionSqlDao.class);
@@ -111,7 +108,6 @@ public class EntitlementSqlDao implements EntitlementDao {
         this.notificationQueueService = notificationQueueService;
         this.addonUtils = addonUtils;
         this.customFieldDao = customFieldDao;
-        this.overdueApi = overdueApi;
         this.catalogService = catalogService;
     }
 
@@ -123,12 +119,12 @@ public class EntitlementSqlDao implements EntitlementDao {
     @Override
     public List<SubscriptionBundle> getSubscriptionBundleForAccount(
             final UUID accountId) {
-        return applyOverdueState(bundlesDao.getBundleFromAccount(accountId.toString()));
+        return bundlesDao.getBundleFromAccount(accountId.toString());
     }
 
     @Override
     public SubscriptionBundle getSubscriptionBundleFromId(final UUID bundleId) {
-        return applyOverdueState(bundlesDao.getBundleFromId(bundleId.toString()));
+        return bundlesDao.getBundleFromId(bundleId.toString());
     }
 
     @Override
@@ -227,12 +223,7 @@ public class EntitlementSqlDao implements EntitlementDao {
 
                 recordFutureNotificationFromTransaction(dao,
                         nextPhase.getEffectiveDate(),
-                        new NotificationKey() {
-                            @Override
-                            public String toString() {
-                                return nextPhase.getId().toString();
-                            }
-                        });
+                        new EntitlementNotificationKey(nextPhase.getId()));
                 return null;
             }
         });
@@ -274,12 +265,7 @@ public class EntitlementSqlDao implements EntitlementDao {
                     eventIds.add(cur.getId().toString()); // collect ids for batch audit log insert
                     recordFutureNotificationFromTransaction(dao,
                             cur.getEffectiveDate(),
-                            new NotificationKey() {
-                                @Override
-                                public String toString() {
-                                    return cur.getId().toString();
-                                }
-                            });
+                            new EntitlementNotificationKey(cur.getId()));
                 }
 
                 AuditSqlDao auditSqlDao = dao.become(AuditSqlDao.class);
@@ -304,12 +290,8 @@ public class EntitlementSqlDao implements EntitlementDao {
                     eventIds.add(cur.getId().toString()); // gather event ids for batch audit insert
                     recordFutureNotificationFromTransaction(dao,
                             cur.getEffectiveDate(),
-                            new NotificationKey() {
-                                @Override
-                                public String toString() {
-                                    return cur.getId().toString();
-                                }
-                            });
+                            new EntitlementNotificationKey(cur.getId()));
+
                 }
 
                 AuditSqlDao auditSqlDao = dao.become(AuditSqlDao.class);
@@ -320,7 +302,7 @@ public class EntitlementSqlDao implements EntitlementDao {
     }
 
     @Override
-    public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context) {
+    public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context, final int seqId) {
 
         eventsDao.inTransaction(new Transaction<Void, EventSqlDao>() {
             @Override
@@ -336,12 +318,7 @@ public class EntitlementSqlDao implements EntitlementDao {
 
                 recordFutureNotificationFromTransaction(dao,
                         cancelEvent.getEffectiveDate(),
-                        new NotificationKey() {
-                            @Override
-                            public String toString() {
-                                return cancelEvent.getId().toString();
-                            }
-                        });
+                        new EntitlementNotificationKey(cancelEvent.getId(), seqId));
                 return null;
             }
         });
@@ -379,12 +356,7 @@ public class EntitlementSqlDao implements EntitlementDao {
                         eventIds.add(cur.getId().toString()); // gather event ids for batch insert into audit log
                         recordFutureNotificationFromTransaction(dao,
                                 cur.getEffectiveDate(),
-                                new NotificationKey() {
-                                    @Override
-                                    public String toString() {
-                                        return cur.getId().toString();
-                                    }
-                                });
+                                new EntitlementNotificationKey(cur.getId()));
                     }
 
                     AuditSqlDao auditSqlDao = dao.become(AuditSqlDao.class);
@@ -411,12 +383,7 @@ public class EntitlementSqlDao implements EntitlementDao {
 
                     recordFutureNotificationFromTransaction(dao,
                             cur.getEffectiveDate(),
-                            new NotificationKey() {
-                                @Override
-                                public String toString() {
-                                    return cur.getId().toString();
-                                }
-                            });
+                            new EntitlementNotificationKey(cur.getId()));
                 }
 
                 AuditSqlDao auditSqlDao = dao.become(AuditSqlDao.class);
@@ -439,8 +406,8 @@ public class EntitlementSqlDao implements EntitlementDao {
     }
 
     private void cancelFutureEventFromTransaction(final UUID subscriptionId, final EventSqlDao dao,
-                                                  final EventType type, @Nullable final ApiEventType apiType,
-                                                  final CallContext context) {
+            final EventType type, @Nullable final ApiEventType apiType,
+            final CallContext context) {
 
         UUID futureEventId = null;
         Date now = clock.getUTCNow().toDate();
@@ -466,8 +433,8 @@ public class EntitlementSqlDao implements EntitlementDao {
     }
 
     private void updateCustomFieldsFromTransaction(final SubscriptionSqlDao transactionalDao,
-                                                   final SubscriptionData subscription,
-                                                   final CallContext context) {
+            final SubscriptionData subscription,
+            final CallContext context) {
         customFieldDao.saveFields(transactionalDao, subscription.getId(), subscription.getObjectName(), subscription.getFieldList(), context);
     }
 
@@ -488,8 +455,8 @@ public class EntitlementSqlDao implements EntitlementDao {
             if (cur.getId().equals(input.getId())) {
                 return cur;
             }
-         }
-         throw new EntitlementError(String.format("Unexpected code path in buildSubscription"));
+        }
+        throw new EntitlementError(String.format("Unexpected code path in buildSubscription"));
     }
 
     private List<Subscription> buildBundleSubscriptions(final SubscriptionFactory factory, final List<Subscription> input) {
@@ -508,7 +475,7 @@ public class EntitlementSqlDao implements EntitlementDao {
         });
 
         EntitlementEvent futureBaseEvent = null;
-                List<Subscription> result = new ArrayList<Subscription>(input.size());
+        List<Subscription> result = new ArrayList<Subscription>(input.size());
         for (Subscription cur : input) {
 
             List<EntitlementEvent> events = eventsDao.getEventsForSubscription(cur.getId().toString());
@@ -531,28 +498,28 @@ public class EntitlementSqlDao implements EntitlementDao {
                 String baseProductName = (futureBaseEvent instanceof ApiEventChange) ?
                         ((ApiEventChange) futureBaseEvent).getEventPlan() : null;
 
-                boolean createCancelEvent = (futureBaseEvent != null) &&
-                    ((futureBaseEvent instanceof ApiEventCancel) ||
-                            ((! addonUtils.isAddonAvailable(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
-                                    (addonUtils.isAddonIncluded(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
-
-                if (createCancelEvent) {
-                    DateTime now = clock.getUTCNow();
-                    EntitlementEvent addOnCancelEvent = new ApiEventCancel(new ApiEventBuilder()
-                    .setSubscriptionId(reloaded.getId())
-                    .setActiveVersion(((SubscriptionData) reloaded).getActiveVersion())
-                    .setProcessedDate(now)
-                    .setEffectiveDate(futureBaseEvent.getEffectiveDate())
-                    .setRequestedDate(now)
-                    // This event is only there to indicate the ADD_ON is future canceled, but it is not there
-                    // on disk until the base plan cancellation becomes effective
-                    .setFromDisk(false));
-
-                    events.add(addOnCancelEvent);
-                    // Finally reload subscription with full set of events
-                    reloaded = factory.createSubscription(new SubscriptionBuilder((SubscriptionData) cur), events);
-                }
-                break;
+                        boolean createCancelEvent = (futureBaseEvent != null) &&
+                        ((futureBaseEvent instanceof ApiEventCancel) ||
+                                ((! addonUtils.isAddonAvailable(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
+                                        (addonUtils.isAddonIncluded(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
+
+                        if (createCancelEvent) {
+                            DateTime now = clock.getUTCNow();
+                            EntitlementEvent addOnCancelEvent = new ApiEventCancel(new ApiEventBuilder()
+                            .setSubscriptionId(reloaded.getId())
+                            .setActiveVersion(((SubscriptionData) reloaded).getActiveVersion())
+                            .setProcessedDate(now)
+                            .setEffectiveDate(futureBaseEvent.getEffectiveDate())
+                            .setRequestedDate(now)
+                            // This event is only there to indicate the ADD_ON is future canceled, but it is not there
+                            // on disk until the base plan cancellation becomes effective
+                            .setFromDisk(false));
+
+                            events.add(addOnCancelEvent);
+                            // Finally reload subscription with full set of events
+                            reloaded = factory.createSubscription(new SubscriptionBuilder((SubscriptionData) cur), events);
+                        }
+                        break;
             default:
                 break;
             }
@@ -590,12 +557,7 @@ public class EntitlementSqlDao implements EntitlementDao {
 
                             recordFutureNotificationFromTransaction(transEventDao,
                                     curEvent.getEffectiveDate(),
-                                    new NotificationKey() {
-                                @Override
-                                public String toString() {
-                                    return curEvent.getId().toString();
-                                }
-                            });
+                                    new EntitlementNotificationKey(curEvent.getId()));
                         }
                         transSubDao.insertSubscription(subData, context);
                         subscriptionIds.add(subData.getId().toString()); // gather subscription ids for batch audit
@@ -629,7 +591,7 @@ public class EntitlementSqlDao implements EntitlementDao {
     private void recordFutureNotificationFromTransaction(final Transmogrifier transactionalDao, final DateTime effectiveDate, final NotificationKey notificationKey) {
         try {
             NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(Engine.ENTITLEMENT_SERVICE_NAME,
-                Engine.NOTIFICATION_QUEUE_NAME);
+                    Engine.NOTIFICATION_QUEUE_NAME);
             subscriptionEventQueue.recordFutureNotificationFromTransaction(transactionalDao, effectiveDate, notificationKey);
         } catch (NoSuchNotificationQueue e) {
             throw new RuntimeException(e);
@@ -657,22 +619,4 @@ public class EntitlementSqlDao implements EntitlementDao {
         }
     }
  
-    private List<SubscriptionBundle> applyOverdueState(final List<SubscriptionBundle> bundles)  { 
-        List<SubscriptionBundle> result = new ArrayList<SubscriptionBundle>();
-        for(SubscriptionBundle bundle : bundles) {
-            result.add(applyOverdueState(bundle));
-        }
-        return result;
-    }
-
-    private SubscriptionBundle applyOverdueState(final SubscriptionBundle bundle)  {
-        try {
-            String name = overdueApi.getOverdueStateNameFor(bundle);
-            OverdueState<SubscriptionBundle> state = catalogService.getCurrentCatalog().currentBundleOverdueStateSet().findState(name);
-            return new SubscriptionBundleData(bundle.getId(),bundle.getKey(),bundle.getAccountId(), bundle.getStartDate(), state);
-        } catch (CatalogApiException e) {
-           throw new EntitlementError(e);
-        }
-    }
-    
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EventSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EventSqlDao.java
index 0c2ba04..89baed8 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EventSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EventSqlDao.java
@@ -77,15 +77,29 @@ public interface EventSqlDao extends Transactional<EventSqlDao>, CloseMe, Transm
     public static class EventSqlDaoBinder extends BinderBase implements Binder<Bind, EntitlementEvent> {
         @Override
         public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, EntitlementEvent evt) {
+        	
+        	String planName = null;
+        	String phaseName = null;
+        	String priceListName = null;
+        	String userType = null;
+        	if (evt.getType() == EventType.API_USER) {
+        		ApiEvent userEvent = (ApiEvent) evt;
+            	planName = userEvent.getEventPlan();
+            	phaseName = userEvent.getEventPlanPhase();
+            	priceListName = userEvent.getPriceList();
+            	userType = userEvent.getEventType().toString();
+        	} else {
+        		phaseName = ((PhaseEvent) evt).getPhase();
+        	}
             stmt.bind("event_id", evt.getId().toString());
             stmt.bind("event_type", evt.getType().toString());
-            stmt.bind("user_type", (evt.getType() == EventType.API_USER) ? ((ApiEvent) evt).getEventType().toString() : null);
+            stmt.bind("user_type", userType);
             stmt.bind("requested_dt", getDate(evt.getRequestedDate()));
             stmt.bind("effective_dt", getDate(evt.getEffectiveDate()));
             stmt.bind("subscription_id", evt.getSubscriptionId().toString());
-            stmt.bind("plan_name", (evt.getType() == EventType.API_USER) ? ((ApiEvent) evt).getEventPlan() : null);
-            stmt.bind("phase_name", (evt.getType() == EventType.API_USER) ? ((ApiEvent) evt).getEventPlanPhase() : ((PhaseEvent) evt).getPhase());
-            stmt.bind("plist_name", (evt.getType() == EventType.API_USER) ? ((ApiEvent) evt).getPriceList() : null);
+            stmt.bind("plan_name", planName);
+            stmt.bind("phase_name", phaseName);
+            stmt.bind("plist_name", priceListName);
             stmt.bind("current_version", evt.getActiveVersion());
             stmt.bind("is_active", evt.isActive());
         }
@@ -109,7 +123,8 @@ public interface EventSqlDao extends Transactional<EventSqlDao>, CloseMe, Transm
             String priceListName = r.getString("plist_name");
             long currentVersion = r.getLong("current_version");
             boolean isActive = r.getBoolean("is_active");
-
+            UUID userToken = r.getString("user_token") != null ? UUID.fromString(r.getString("user_token")) : null;
+            
             EventBaseBuilder<?> base = ((eventType == EventType.PHASE) ?
                     new PhaseEventBuilder() :
                         new ApiEventBuilder())
@@ -131,6 +146,7 @@ public interface EventSqlDao extends Transactional<EventSqlDao>, CloseMe, Transm
                     .setEventPlanPhase(phaseName)
                     .setEventPriceList(priceListName)
                     .setEventType(userType)
+                    .setUserToken(userToken)
                     .setFromDisk(true);
 
                 if (userType == ApiEventType.CREATE) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEvent.java
index c26b168..20a6569 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEvent.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.entitlement.events.user;
 
+import java.util.UUID;
+
 import com.ning.billing.entitlement.events.EntitlementEvent;
 
 
@@ -30,5 +32,7 @@ public interface ApiEvent extends EntitlementEvent {
     public String getPriceList();
 
     public boolean isFromDisk();
+    
+    public UUID getUserToken();
 
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
index f67c6b7..c68da2b 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
@@ -28,6 +28,7 @@ public class ApiEventBase extends EventBase implements ApiEvent {
     private final String eventPlan;
     private final String eventPlanPhase;
     private final String eventPriceList;
+    private final UUID userToken;
     private final boolean fromDisk;
 
     public ApiEventBase(ApiEventBuilder builder) {
@@ -37,28 +38,9 @@ public class ApiEventBase extends EventBase implements ApiEvent {
         this.eventPlan = builder.getEventPlan();
         this.eventPlanPhase = builder.getEventPlanPhase();
         this.fromDisk = builder.isFromDisk();
+        this.userToken = builder.getUserToken();
     }
 
-/*
-    public ApiEventBase(UUID subscriptionId, DateTime bundleStartDate, DateTime processed, String planName, String phaseName,
-            String priceList, DateTime requestedDate,  ApiEventType eventType, DateTime effectiveDate, long activeVersion) {
-        super(subscriptionId, requestedDate, effectiveDate, processed, activeVersion, true);
-        this.eventType = eventType;
-        this.eventPriceList = priceList;
-        this.eventPlan = planName;
-        this.eventPlanPhase = phaseName;
-    }
-
-    public ApiEventBase(UUID subscriptionId, DateTime bundleStartDate, DateTime processed,
-            DateTime requestedDate,  ApiEventType eventType, DateTime effectiveDate, long activeVersion) {
-        super(subscriptionId, requestedDate, effectiveDate, processed, activeVersion, true);
-        this.eventType = eventType;
-        this.eventPriceList = null;
-        this.eventPlan = null;
-        this.eventPlanPhase = null;
-    }
-*/
-
     @Override
     public ApiEventType getEventType() {
         return eventType;
@@ -83,6 +65,12 @@ public class ApiEventBase extends EventBase implements ApiEvent {
     public String getPriceList() {
         return eventPriceList;
     }
+    
+	@Override
+	public UUID getUserToken() {
+		return userToken;
+	}
+
 
     @Override
     public boolean isFromDisk() {
@@ -105,6 +93,7 @@ public class ApiEventBase extends EventBase implements ApiEvent {
                 + ", getActiveVersion()=" + getActiveVersion()
                 + ", getProcessedDate()=" + getProcessedDate()
                 + ", getSubscriptionId()=" + getSubscriptionId()
+                + ", evetnToken()=" + getUserToken()
                 + ", isActive()=" + isActive() + "]";
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBuilder.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBuilder.java
index b7e9764..b6be427 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBuilder.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBuilder.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.entitlement.events.user;
 
+import java.util.UUID;
+
 import com.ning.billing.entitlement.events.EventBaseBuilder;
 
 public class ApiEventBuilder extends EventBaseBuilder<ApiEventBuilder> {
@@ -24,6 +26,7 @@ public class ApiEventBuilder extends EventBaseBuilder<ApiEventBuilder> {
     private String eventPlan;
     private String eventPlanPhase;
     private String eventPriceList;
+    private UUID userToken;
     private boolean fromDisk;
 
 
@@ -50,11 +53,21 @@ public class ApiEventBuilder extends EventBaseBuilder<ApiEventBuilder> {
     public String getEventPriceList() {
         return eventPriceList;
     }
+    
+    public UUID getUserToken() {
+    	return userToken;
+    }
 
     public boolean isFromDisk() {
         return fromDisk;
     }
 
+    public ApiEventBuilder setUserToken(UUID userToken) {
+        this.userToken = userToken;
+        return this;
+    }
+
+    
     public ApiEventBuilder setFromDisk(boolean fromDisk) {
         this.fromDisk = fromDisk;
         return this;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventType.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventType.java
index a279f52..27d5b61 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventType.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventType.java
@@ -16,7 +16,7 @@
 
 package com.ning.billing.entitlement.events.user;
 
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 
 
 public enum ApiEventType {
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 055f465..dea0aea 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
@@ -27,8 +27,6 @@ import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.entitlement.api.migration.DefaultEntitlementMigrationApi;
 import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
-import com.ning.billing.entitlement.api.overdue.DefaultOverdueChecker;
-import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.SubscriptionApiService;
@@ -48,10 +46,6 @@ public class EntitlementModule extends AbstractModule {
         bind(EntitlementDao.class).to(EntitlementSqlDao.class).asEagerSingleton();
     }
     
-    protected void installOverdueChecker() {
-        bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();       
-    }
-
     protected void installEntitlementCore() {
     	bind(SubscriptionFactory.class).asEagerSingleton();
         bind(SubscriptionApiService.class).asEagerSingleton();
@@ -70,6 +64,5 @@ public class EntitlementModule extends AbstractModule {
         installConfig();
         installEntitlementDao();
         installEntitlementCore();
-        installOverdueChecker();
     }
 }
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
index bef27aa..d2bb5b7 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
@@ -11,6 +11,7 @@ CREATE TABLE entitlement_events (
     plan_name varchar(64) DEFAULT NULL,
     phase_name varchar(128) DEFAULT NULL,
     plist_name varchar(64) DEFAULT NULL,
+    user_token char(36),
     current_version int(11) DEFAULT 1,
     is_active bool DEFAULT 1,
     created_by varchar(50) NOT NULL,
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/EventSqlDao.sql.stg b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/EventSqlDao.sql.stg
index 9179943..cd5afbf 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/EventSqlDao.sql.stg
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/EventSqlDao.sql.stg
@@ -10,6 +10,7 @@ fields(prefix) ::= <<
     <prefix>plan_name,
     <prefix>phase_name,
     <prefix>plist_name,
+    <prefix>user_token,
     <prefix>current_version,
     <prefix>is_active,
     <prefix>created_by,
@@ -18,6 +19,7 @@ fields(prefix) ::= <<
     <prefix>updated_date
 >>
 
+
 getEventById() ::= <<
   select id, <fields()>
   from entitlement_events
@@ -29,21 +31,22 @@ getEventById() ::= <<
 insertEvent() ::= <<
     insert into entitlement_events (<fields()>)
     values (
-      :event_id
-      , :event_type
-      , :user_type
-      , :requested_dt
-      , :effective_dt
-      , :subscription_id
-      , :plan_name
-      , :phase_name
-      , :plist_name
-      , :current_version
-      , :is_active
-      , :userName
-      , :createdDate
-      , :userName
-      , :updatedDate
+    :event_id
+    , :event_type
+    , :user_type
+    , :requested_dt
+    , :effective_dt
+    , :subscription_id
+    , :plan_name
+    , :phase_name
+    , :plist_name
+    , :userToken
+    , :current_version
+    , :is_active
+    , :userName
+    , :createdDate
+    , :userName
+    , :updatedDate
     );   
 >>
 
@@ -69,6 +72,7 @@ reactiveEvent() ::= <<
     ;
 >>
 
+
 getFutureActiveEventForSubscription() ::= <<
     select id, <fields()>
     from entitlement_events
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/ApiTestListener.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/ApiTestListener.java
index 8d8e00c..694613e 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/ApiTestListener.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/ApiTestListener.java
@@ -18,7 +18,7 @@ package com.ning.billing.entitlement.api;
 
 import com.google.common.base.Joiner;
 import com.google.common.eventbus.Subscribe;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.util.bus.Bus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,7 +52,7 @@ public class ApiTestListener {
     }
 
     @Subscribe
-    public void handleEntitlementEvent(SubscriptionTransition event) {
+    public void handleEntitlementEvent(SubscriptionEventTransition event) {
         switch (event.getTransitionType()) {
         case MIGRATE_ENTITLEMENT:
             subscriptionMigrated(event);
@@ -142,33 +142,33 @@ public class ApiTestListener {
     }
 
 
-    public void subscriptionMigrated(SubscriptionTransition migrated) {
+    public void subscriptionMigrated(SubscriptionEventTransition migrated) {
         log.debug("-> Got event MIGRATED");
         assertEqualsNicely(NextEvent.MIGRATE_ENTITLEMENT);
         notifyIfStackEmpty();
     }
 
-    public void subscriptionCreated(SubscriptionTransition created) {
+    public void subscriptionCreated(SubscriptionEventTransition created) {
         log.debug("-> Got event CREATED");
         assertEqualsNicely(NextEvent.CREATE);
         notifyIfStackEmpty();
     }
 
-    public void subscriptionReCreated(SubscriptionTransition recreated) {
+    public void subscriptionReCreated(SubscriptionEventTransition recreated) {
         log.debug("-> Got event RE_CREATED");
         assertEqualsNicely(NextEvent.RE_CREATE);
         notifyIfStackEmpty();
     }
 
 
-    public void subscriptionCancelled(SubscriptionTransition cancelled) {
+    public void subscriptionCancelled(SubscriptionEventTransition cancelled) {
         log.debug("-> Got event CANCEL");
         assertEqualsNicely(NextEvent.CANCEL);
         notifyIfStackEmpty();
     }
 
 
-    public void subscriptionChanged(SubscriptionTransition changed) {
+    public void subscriptionChanged(SubscriptionEventTransition changed) {
         log.debug("-> Got event CHANGE");
         assertEqualsNicely(NextEvent.CHANGE);
         notifyIfStackEmpty();
@@ -176,13 +176,13 @@ public class ApiTestListener {
 
 
     public void subscriptionPhaseChanged(
-            SubscriptionTransition phaseChanged) {
+            SubscriptionEventTransition phaseChanged) {
         log.debug("-> Got event PHASE");
         assertEqualsNicely(NextEvent.PHASE);
         notifyIfStackEmpty();
     }
 
-    public void subscriptionMigratedBilling(SubscriptionTransition migrated) {
+    public void subscriptionMigratedBilling(SubscriptionEventTransition migrated) {
         log.debug("-> Got event MIGRATED_BLLING");
         assertEqualsNicely(NextEvent.MIGRATE_BILLING);
         notifyIfStackEmpty();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
index 9a5af34..24affef 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
@@ -38,7 +38,7 @@ import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
index 68f5cbb..9104bce 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
@@ -54,7 +54,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
@@ -76,7 +76,7 @@ public class TestDefaultEntitlementBillingApi {
 	private CatalogService catalogService;
 	private ArrayList<SubscriptionBundle> bundles;
 	private ArrayList<Subscription> subscriptions;
-	private ArrayList<SubscriptionTransition> transitions;
+	private ArrayList<SubscriptionEventTransition> transitions;
 	private EntitlementDao dao;
 
 	private Clock clock;
@@ -101,7 +101,7 @@ public class TestDefaultEntitlementBillingApi {
 		bundles.add(bundle);
 
 
-		transitions = new ArrayList<SubscriptionTransition>();
+		transitions = new ArrayList<SubscriptionEventTransition>();
 		subscriptions = new ArrayList<Subscription>();
 
 		SubscriptionBuilder builder = new SubscriptionBuilder();
@@ -109,7 +109,7 @@ public class TestDefaultEntitlementBillingApi {
 		builder.setStartDate(subscriptionStartDate).setId(oneId);
 		subscription = new SubscriptionData(builder) {
 		    @Override
-            public List<SubscriptionTransition> getBillingTransitions() {
+            public List<SubscriptionEventTransition> getBillingTransitions() {
 		    	return transitions;
 		    }
 		};
@@ -153,8 +153,8 @@ public class TestDefaultEntitlementBillingApi {
 		Plan nextPlan = catalogService.getFullCatalog().findPlan("shotgun-annual", now);
 		PlanPhase nextPhase = nextPlan.getAllPhases()[0]; // The trial has no billing period
         PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
-		SubscriptionTransition t = new SubscriptionTransitionData(
-				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, true);
+		SubscriptionEventTransition t = new SubscriptionTransitionData(
+				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, null, true);
 		transitions.add(t);
 
 
@@ -181,8 +181,8 @@ public class TestDefaultEntitlementBillingApi {
 		Plan nextPlan = catalogService.getFullCatalog().findPlan("shotgun-annual", now);
 		PlanPhase nextPhase = nextPlan.getAllPhases()[1];
 		PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
-		SubscriptionTransition t = new SubscriptionTransitionData(
-				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, true);
+		SubscriptionEventTransition t = new SubscriptionTransitionData(
+				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, null, true);
 		transitions.add(t);
 
 		Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
@@ -210,8 +210,8 @@ public class TestDefaultEntitlementBillingApi {
 		Plan nextPlan = catalogService.getFullCatalog().findPlan("shotgun-monthly", now);
 		PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
-		SubscriptionTransition t = new SubscriptionTransitionData(
-				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, true);
+		SubscriptionEventTransition t = new SubscriptionTransitionData(
+				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, null, true);
 		transitions.add(t);
 
         AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -237,8 +237,8 @@ public class TestDefaultEntitlementBillingApi {
 		Plan nextPlan = catalogService.getFullCatalog().findPlan("laser-scope-monthly", now);
 		PlanPhase nextPhase = nextPlan.getAllPhases()[0];
         PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
-		SubscriptionTransition t = new SubscriptionTransitionData(
-				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, true);
+		SubscriptionEventTransition t = new SubscriptionTransitionData(
+				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, null, true);
 		transitions.add(t);
 
 		Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java
index 06d2ae1..febf63c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java
@@ -16,756 +16,707 @@
 
 package com.ning.billing.entitlement.api.billing;
 
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.UUID;
-
-import org.joda.time.DateTime;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.ning.billing.account.api.Account;
-import com.ning.billing.catalog.MockCatalog;
-import com.ning.billing.catalog.MockPlan;
-import com.ning.billing.catalog.MockPlanPhase;
-import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.catalog.api.Plan;
-import com.ning.billing.catalog.api.PlanPhase;
-import com.ning.billing.catalog.api.overdue.Overdueable;
-import com.ning.billing.catalog.api.overdue.Overdueable.Type;
-import com.ning.billing.catalog.overdue.DefaultOverdueState;
-import com.ning.billing.catalog.overdue.MockOverdueRules;
-import com.ning.billing.catalog.overdue.MockOverdueState;
-import com.ning.billing.catalog.overdue.MockOverdueStatesBundle;
-import com.ning.billing.catalog.overdue.OverdueRules;
-import com.ning.billing.catalog.overdue.OverdueStatesBundle;
-import com.ning.billing.entitlement.api.billing.OverdueEventCalculator.DisabledDuration;
-import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
-import com.ning.billing.mock.BrainDeadProxyFactory;
-import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.ClockMock;
-import com.ning.billing.util.overdue.OverdueAccessApi;
-import com.ning.billing.util.overdue.OverdueEvent;
-import com.ning.billing.util.overdue.dao.OverdueAccessDao;
 
 public class TestOverdueEventCalculator {
 
-    private static final String DISABLED_BUNDLE = "disabled-bundle";
-    private static final String CLEAR_BUNDLE = "clear-bundle";
-    
-    
-    private static final DefaultOverdueState<SubscriptionBundle> CLEAR_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(CLEAR_BUNDLE, false, false); 
-    private static final DefaultOverdueState<SubscriptionBundle> DISABLED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_BUNDLE, false, true);
-
-    private OverdueAccessApi overdueAccessApi;
-    private Account account;
-    private Subscription subscription1;
-    private Subscription subscription2;
-    private Subscription subscription3;
-    private Subscription subscription4;
-    private UUID bundleId1 = UUID.randomUUID();
-    private UUID bundleId2 = UUID.randomUUID();
-    private Clock clock;
-    private OverdueEventCalculator odc;
-
-    @BeforeClass
-    public void setUpBeforeClass() throws Exception {
-
-        @SuppressWarnings("unchecked")
-        final OverdueStatesBundle bundleODS =  new MockOverdueStatesBundle(new DefaultOverdueState[] {
-                CLEAR_BUNDLE_STATE, DISABLED_BUNDLE_STATE    });
-
-        clock = new ClockMock();
-        
-        Injector i = Guice.createInjector(new AbstractModule() {
-
-            @Override
-            protected void configure() {
-                overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
-                account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
-                subscription1 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
-                subscription2 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
-                subscription3 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
-                subscription4 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
-                ((ZombieControl) subscription1).addResult("getBundleId", bundleId1);
-                ((ZombieControl) subscription2).addResult("getBundleId", bundleId1);
-                ((ZombieControl) subscription3).addResult("getBundleId", bundleId1);
-                ((ZombieControl) subscription4).addResult("getBundleId", bundleId2);
-                ((ZombieControl) subscription1).addResult("compareTo", 1);
-                ((ZombieControl) subscription2).addResult("compareTo", 1);
-                ((ZombieControl) subscription3).addResult("compareTo", 1);
-                ((ZombieControl) subscription4).addResult("compareTo", 1);
-                ((ZombieControl) subscription1).addResult("getId", UUID.randomUUID());
-                ((ZombieControl) subscription2).addResult("getId", UUID.randomUUID());
-                ((ZombieControl) subscription3).addResult("getId", UUID.randomUUID());
-                ((ZombieControl) subscription4).addResult("getId", UUID.randomUUID());
-         
-              //  bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();
-                CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
-                ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog() {
-
-                    @Override
-                    public void setOverdueRules() {
-                         OverdueRules overdueRules = new MockOverdueRules().setOverdueStatesBundle(bundleODS);                       
-                        setOverdueRules(overdueRules);  
-                    }
-                    
-                });
-                bind(CatalogService.class).toInstance(catalogService);
-                               
-               
-                bind(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
-                bind(OverdueAccessApi.class).toInstance(overdueAccessApi);              
-                              
-            }
-            
-        });
-        odc = i.getInstance(OverdueEventCalculator.class);
-
-    }
-
-    @Test
-    // S1-S2-S3 subscriptions in B1
-    // B1 -----[--------]
-    // S1 --A-------------------------------------
-    // S2 --B------C------------------------------
-    // S3 ------------------D---------------------
-    
-
-    //Result
-    // S1 --A--[-------]--------------------------
-    // S2 --B--[-------]--------------------------
-    // S3 ------------------D---------------------
-    
-    public void testInsertOverdueEvents() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, null));
-        BillingEvent A = createRealEvent(now.minusDays(1).minusHours(1), subscription1);
-        BillingEvent B = createRealEvent(now.minusDays(1), subscription2);
-        BillingEvent C = createRealEvent(now.plusDays(1), subscription2);
-        BillingEvent D = createRealEvent(now.plusDays(3), subscription3);
-        billingEvents.add(A);
-        billingEvents.add(B);
-        billingEvents.add(C);
-        billingEvents.add(D);
-
-        SortedSet<OverdueEvent> overdueBundleEvents = new TreeSet<OverdueEvent>();
-        overdueBundleEvents.add(new OverdueEvent(bundleId1,DISABLED_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now));
-        overdueBundleEvents.add(new OverdueEvent(bundleId1,CLEAR_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now.plusDays(2)));
-        
-        ((ZombieControl)overdueAccessApi).addResult("getOverdueHistory", overdueBundleEvents);
-        
-        
-        odc.insertOverdueEvents(billingEvents);
-        
-        assertEquals(billingEvents.size(), 7);
-        
-        SortedSet<BillingEvent> s1Events = odc.filter(billingEvents, subscription1);
-        Iterator<BillingEvent> it1 = s1Events.iterator();
-        assertEquals(it1.next(), A);
-        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
-        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
-        
-        SortedSet<BillingEvent> s2Events = odc.filter(billingEvents, subscription2);
-        Iterator<BillingEvent> it2 = s2Events.iterator();       
-        assertEquals(it2.next(), B);
-        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
-        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
-                
-        SortedSet<BillingEvent> s3Events = odc.filter(billingEvents, subscription3);
-        Iterator<BillingEvent> it3 = s3Events.iterator();       
-        assertEquals(it3.next(),D);
-    }
-
-    // Open ended duration with a previous event
-    // --X--[----------------------------------
-   @Test
-    public void testEventsToRemoveOpenPrev() {
-       DateTime now = clock.getUTCNow();
-       List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-       SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-       
-       disabledDuration.add(new DisabledDuration(now, null));
-       billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
-       
-       SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
-       
-       assertEquals(results.size(), 0);
-   }
-
-   // Open with previous and following events
-   // --X--[----Y-----------------------------
-    @Test
-    public void testEventsToRemoveOpenPrevFollow() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, null));
-        BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
-        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
-        billingEvents.add(e1);
-        billingEvents.add(e2);
-        
-        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
-        
-        assertEquals(results.size(), 1);
-        assertEquals(results.first(), e2);
-    }
-
-    // Open with no previous event (only following)
-    // -----[----X-----------------------------
-    @Test
-    public void testEventsToRemoveOpenFollow() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, null));
-        BillingEvent e1  = createRealEvent(now.plusDays(1), subscription1);
-        billingEvents.add(e1);
-        
-        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
-        
-        assertEquals(results.size(), 1);
-        assertEquals(results.first(), e1);
-   }
-
-    // Closed duration with a single previous event
-    // --X--[------------]---------------------
-        @Test
-    public void testEventsToRemoveClosedPrev() {
-            DateTime now = clock.getUTCNow();
-            List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-            SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-            
-            disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-            BillingEvent e1  = createRealEvent(now.minusDays(1), subscription1);
-            billingEvents.add(e1);
-            
-            SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
-            
-            assertEquals(results.size(), 0);
-    }
-
-    // Closed duration with a previous event and in-between event
-    // --X--[------Y-----]---------------------
-    @Test
-    public void testEventsToRemoveClosedPrevBetw() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
-        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
-        
-        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
-        
-        assertEquals(results.size(), 2);
-        assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
-        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
-        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
-    }
-
-    // Closed duration with a previous event and in-between event and following
-    // --X--[------Y-----]-------Z-------------
-    @Test
-    public void testEventsToRemoveClosedPrevBetwNext() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-        BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
-        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
-        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
-        billingEvents.add(e1);
-        billingEvents.add(e2);        
-        billingEvents.add(e3);        
-        
-        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
-        
-        assertEquals(results.size(), 1);
-        assertEquals(results.first(), e2);
-   }
-
-    // Closed with no previous event but in-between events
-    // -----[------Y-----]---------------------
-    @Test
-    public void testEventsToRemoveClosedBetwn() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
-        billingEvents.add(e2);        
-      
-        
-        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
-        
-        assertEquals(results.size(), 1);
-        assertEquals(results.first(), e2);
-    }
-
-    // Closed with no previous event but in-between events and following
-    // -----[------Y-----]-------Z-------------
-    @Test
-    public void testEventsToRemoveClosedBetweenFollow() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-
-        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
-        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
-        billingEvents.add(e2);        
-        billingEvents.add(e3);        
-        
-        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
-        
-        assertEquals(results.size(), 1);
-        assertEquals(results.first(), e2);
-    }
-
-    // Closed duration with only following
-    // -----[------------]-------Z-------------
-    @Test
-    public void testEventsToRemoveClosedFollow() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-
-        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
-       
-        billingEvents.add(e3);        
-        
-        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
-        
-        assertEquals(results.size(), 0);
-     }
-    
-    // Open ended duration with a previous event
-    // --X--[----------------------------------
-   @Test
-    public void testCreateNewEventsOpenPrev() {
-       DateTime now = clock.getUTCNow();
-       List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-       SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-       
-       disabledDuration.add(new DisabledDuration(now, null));
-       billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
-       
-       SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-       
-       assertEquals(results.size(), 1);
-       assertEquals(results.first().getEffectiveDate(), now);
-       assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-       assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
-   }
-
-   // Open with previous and following events
-   // --X--[----Y-----------------------------
-    @Test
-    public void testCreateNewEventsOpenPrevFollow() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, null));
-        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
-        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
-        
-        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-        
-        assertEquals(results.size(), 1);
-        assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
-    }
-
-    // Open with no previous event (only following)
-    // -----[----X-----------------------------
-    @Test
-    public void testCreateNewEventsOpenFollow() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, null));
-        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
-        
-        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-        
-        assertEquals(results.size(), 0);
-   }
-
-    // Closed duration with a single previous event
-    // --X--[------------]---------------------
-        @Test
-    public void testCreateNewEventsClosedPrev() {
-            DateTime now = clock.getUTCNow();
-            List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-            SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-            
-            disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-            billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
-            
-            SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-            
-            assertEquals(results.size(), 2);
-            assertEquals(results.first().getEffectiveDate(), now);
-            assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-            assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
-            assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
-            assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-            assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
-    }
-
-    // Closed duration with a previous event and in-between event
-    // --X--[------Y-----]---------------------
-    @Test
-    public void testCreateNewEventsClosedPrevBetw() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
-        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
-        
-        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-        
-        assertEquals(results.size(), 2);
-        assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
-        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
-        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
-    }
-
-    // Closed duration with a previous event and in-between event and following
-    // --X--[------Y-----]-------Z-------------
-    @Test
-    public void testCreateNewEventsClosedPrevBetwNext() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
-        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
-        billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
-        
-        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-        
-        assertEquals(results.size(), 2);
-        assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
-        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
-        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
-   }
-
-    // Closed with no previous event but in-between events
-    // -----[------Y-----]---------------------
-    @Test
-    public void testCreateNewEventsClosedBetwn() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
-        
-        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-        
-        assertEquals(results.size(), 1);
-        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
-        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
-    }
-
-    // Closed with no previous event but in-between events and following
-    // -----[------Y-----]-------Z-------------
-    @Test
-    public void testCreateNewEventsClosedBetweenFollow() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
-        
-        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-        
-        assertEquals(results.size(), 1);
-        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
-        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
-        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
-    }
-
-    // Closed duration with only following
-    // -----[------------]-------Z-------------
-    @Test
-    public void testCreateNewEventsClosedFollow() {
-        DateTime now = clock.getUTCNow();
-        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
-        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
-        
-        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
-        billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
-        
-        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
-        
-        assertEquals(results.size(), 0);
-     }
-
-    @Test
-    public void testPrecedingBillingEventForSubscription() {
-        DateTime now = new DateTime();
-        
-        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
-
-        events.add(createRealEvent(now.minusDays(10), subscription1));
-        events.add(createRealEvent(now.minusDays(6), subscription1));
-        events.add(createRealEvent(now.minusDays(5), subscription1));
-        events.add(createRealEvent(now.minusDays(1), subscription1));
-        
-        BillingEvent minus11 = odc.precedingBillingEventForSubscription(now.minusDays(11), events, subscription1);
-        assertNull(minus11);
-        
-        BillingEvent minus5andAHalf= odc.precedingBillingEventForSubscription(now.minusDays(5).minusHours(12), events, subscription1);
-        assertNotNull(minus5andAHalf);
-        assertEquals(minus5andAHalf.getEffectiveDate(), now.minusDays(6));
-      
-        
-    }
-    
-    protected BillingEvent createRealEvent(DateTime effectiveDate, Subscription subscription) {
-        final Account account = this.account;
-        final int billCycleDay = 1;
-        final PlanPhase planPhase = new MockPlanPhase();
-        final Plan plan = new MockPlan();
-        final BigDecimal fixedPrice = BigDecimal.TEN;
-        final BigDecimal recurringPrice = BigDecimal.TEN;
-        final Currency currency = Currency.USD;
-        final String description = "";
-        final BillingModeType billingModeType = BillingModeType.IN_ADVANCE;
-        final BillingPeriod billingPeriod = BillingPeriod.MONTHLY;
-        final SubscriptionTransitionType type = SubscriptionTransitionType.CHANGE;
-        final Long totalOrdering = 0L; //TODO
-
-        return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
-                fixedPrice, recurringPrice, currency,
-                billingPeriod, billCycleDay, billingModeType,
-                description, totalOrdering, type);
-    }
-
-
-    @Test
-    public void testFilter() {
-        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
-        
-        events.add(createBillingEvent(subscription1));
-        events.add(createBillingEvent(subscription1));
-        events.add(createBillingEvent(subscription1));
-        events.add(createBillingEvent(subscription2));
-        
-        SortedSet<BillingEvent> result1 = odc.filter(events, subscription1);
-        SortedSet<BillingEvent> result2 = odc.filter(events, subscription2);
-        SortedSet<BillingEvent> result3 = odc.filter(events, subscription3);
-        
-        assertEquals(result1.size(), 3);
-        assertEquals(result1.first().getSubscription(), subscription1);
-        assertEquals(result1.last().getSubscription(), subscription1);
-        assertEquals(result2.size(), 1);
-        assertEquals(result2.first().getSubscription(), subscription2);
-        assertEquals(result3.size(), 0);
-    }
-
-    @Test
-    public void testCreateNewDisableEvent() {
-        DateTime now = clock.getUTCNow();
-        BillingEvent event = new MockBillingEvent();
-        
-        BillingEvent result = odc.createNewDisableEvent(now, event);
-        assertEquals(result.getBillCycleDay(),event.getBillCycleDay());
-        assertEquals(result.getEffectiveDate(), now);
-        assertEquals(result.getPlanPhase(), event.getPlanPhase());
-        assertEquals(result.getPlan(), event.getPlan());
-        assertEquals(result.getFixedPrice(),BigDecimal.ZERO);
-        assertEquals(result.getRecurringPrice(), BigDecimal.ZERO);
-        assertEquals(result.getCurrency(), event.getCurrency());
-        assertEquals(result.getDescription(), "");
-        assertEquals(result.getBillingMode(), event.getBillingMode());
-        assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
-        assertEquals(result.getTransitionType(),  SubscriptionTransitionType.CANCEL);
-        assertEquals(result.getTotalOrdering(), new Long(0));
-    }
-
-    @Test
-    public void testCreateNewReenableEvent() {
-        DateTime now = clock.getUTCNow();
-        BillingEvent event = new MockBillingEvent();
-        
-        BillingEvent result = odc.createNewReenableEvent(now, event);
-        assertEquals(result.getBillCycleDay(),event.getBillCycleDay());
-        assertEquals(result.getEffectiveDate(), now);
-        assertEquals(result.getPlanPhase(), event.getPlanPhase());
-        assertEquals(result.getPlan(), event.getPlan());
-        assertEquals(result.getFixedPrice(),event.getFixedPrice());
-        assertEquals(result.getRecurringPrice(), event.getRecurringPrice());
-        assertEquals(result.getCurrency(), event.getCurrency());
-        assertEquals(result.getDescription(), "");
-        assertEquals(result.getBillingMode(), event.getBillingMode());
-        assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
-        assertEquals(result.getTransitionType(),  SubscriptionTransitionType.RE_CREATE);
-        assertEquals(result.getTotalOrdering(), new Long(0));
-    }
-    
-    private class MockBillingEvent extends DefaultBillingEvent {
-        public MockBillingEvent() {
-            super(account, subscription1, clock.getUTCNow(), null, null, BigDecimal.ZERO, BigDecimal.TEN, Currency.USD, BillingPeriod.ANNUAL,
-                    4, BillingModeType.IN_ADVANCE, "", 3L, SubscriptionTransitionType.CREATE);
-        }        
-    }
-
-    @Test
-    public void testCreateBundleSubscriptionMap() {
-        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
-        events.add(createBillingEvent(subscription1));
-        events.add(createBillingEvent(subscription2));
-        events.add(createBillingEvent(subscription3));
-        events.add(createBillingEvent(subscription4));
-        
-        Hashtable<UUID,Set<Subscription>> map = odc.createBundleSubscriptionMap(events);
-        
-        assertNotNull(map);
-        assertEquals(map.keySet().size(),2);
-        assertEquals(map.get(bundleId1).size(), 3);
-        assertEquals(map.get(bundleId2).size(), 1);
-        
-    }
-
-    private BillingEvent createBillingEvent(Subscription subscription) {
-        BillingEvent result =  BrainDeadProxyFactory.createBrainDeadProxyFor(BillingEvent.class, Comparable.class);
-        ((ZombieControl)result).addResult("getSubscription", subscription);
-        ((ZombieControl)result).addResult("compareTo", 1);
-        return result;
-    }
-
-    @Test
-    public void testCreateDisablePairs() {
-        SortedSet<OverdueEvent> overdueBundleEvents;
-        UUID ovdId = UUID.randomUUID();
-        DateTime now = clock.getUTCNow();
-        
-        //simple events open clear -> disabled
-        overdueBundleEvents = new TreeSet<OverdueEvent>();
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
-        
-        List<DisabledDuration> pairs = odc.createDisablePairs(overdueBundleEvents);
-        assertEquals(pairs.size(), 1);
-        assertNotNull(pairs.get(0).getStart());
-        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
-        assertNull(pairs.get(0).getEnd());
-        
-        //simple events closed clear -> disabled
-        overdueBundleEvents = new TreeSet<OverdueEvent>();
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
-        
-        pairs = odc.createDisablePairs(overdueBundleEvents);
-        assertEquals(pairs.size(), 1);
-        assertNotNull(pairs.get(0).getStart());
-        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
-        assertNotNull(pairs.get(0).getEnd());
-        assertEquals(pairs.get(0).getEnd(),now.plusDays(2));
-
-        //simple BUNDLE events closed clear -> disabled
-        overdueBundleEvents = new TreeSet<OverdueEvent>();
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
-        
-        pairs = odc.createDisablePairs(overdueBundleEvents);
-        assertEquals(pairs.size(), 1);
-        assertNotNull(pairs.get(0).getStart());
-        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
-        assertNotNull(pairs.get(0).getEnd());
-        assertEquals(pairs.get(0).getEnd(),now.plusDays(2));
-        
-        
-        //two or more disableds in a row
-        overdueBundleEvents = new TreeSet<OverdueEvent>();
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(3)));
-        
-        pairs = odc.createDisablePairs(overdueBundleEvents);
-        assertEquals(pairs.size(), 1);
-        assertNotNull(pairs.get(0).getStart());
-        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
-        assertNotNull(pairs.get(0).getEnd());
-        assertEquals(pairs.get(0).getEnd(),now.plusDays(3));
-
-       
-        overdueBundleEvents = new TreeSet<OverdueEvent>();
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(3)));
-        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(4)));
-        
-        pairs = odc.createDisablePairs(overdueBundleEvents);
-        assertEquals(pairs.size(), 1);
-        assertNotNull(pairs.get(0).getStart());
-        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
-        assertNotNull(pairs.get(0).getEnd());
-        assertEquals(pairs.get(0).getEnd(),now.plusDays(4));
-  
-    }
-
-    @Test
-    public void testIsDisableEvent() {
-       DateTime now = clock.getUTCNow();
-           assertTrue(!odc.isDisableEvent(new OverdueEvent(new UUID(0L,0L), CLEAR_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now)));
-       assertTrue(odc.isDisableEvent(new OverdueEvent(new UUID(0L,0L), DISABLED_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now)));
-    }
-
+    //TODO MDW refactoring
+//    private static final String DISABLED_BUNDLE = "disabled-bundle";
+//    private static final String CLEAR_BUNDLE = "clear-bundle";
+//    
+//    
+//    private static final DefaultOverdueState<SubscriptionBundle> CLEAR_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(CLEAR_BUNDLE, false, false); 
+//    private static final DefaultOverdueState<SubscriptionBundle> DISABLED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_BUNDLE, false, true);
+//
+//    private OverdueAccessApi overdueAccessApi;
+//    private Account account;
+//    private Subscription subscription1;
+//    private Subscription subscription2;
+//    private Subscription subscription3;
+//    private Subscription subscription4;
+//    private UUID bundleId1 = UUID.randomUUID();
+//    private UUID bundleId2 = UUID.randomUUID();
+//    private Clock clock;
+//    private OverdueEventCalculator odc;
+//
+//    @BeforeClass
+//    public void setUpBeforeClass() throws Exception {
+//
+//        @SuppressWarnings("unchecked")
+//        final OverdueStatesBundle bundleODS =  new MockOverdueStatesBundle(new DefaultOverdueState[] {
+//                CLEAR_BUNDLE_STATE, DISABLED_BUNDLE_STATE    });
+//
+//        clock = new ClockMock();
+//        
+//        Injector i = Guice.createInjector(new AbstractModule() {
+//
+//            @Override
+//            protected void configure() {
+//                overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
+//                account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+//                subscription1 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+//                subscription2 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+//                subscription3 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+//                subscription4 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+//                ((ZombieControl) subscription1).addResult("getBundleId", bundleId1);
+//                ((ZombieControl) subscription2).addResult("getBundleId", bundleId1);
+//                ((ZombieControl) subscription3).addResult("getBundleId", bundleId1);
+//                ((ZombieControl) subscription4).addResult("getBundleId", bundleId2);
+//                ((ZombieControl) subscription1).addResult("compareTo", 1);
+//                ((ZombieControl) subscription2).addResult("compareTo", 1);
+//                ((ZombieControl) subscription3).addResult("compareTo", 1);
+//                ((ZombieControl) subscription4).addResult("compareTo", 1);
+//                ((ZombieControl) subscription1).addResult("getId", UUID.randomUUID());
+//                ((ZombieControl) subscription2).addResult("getId", UUID.randomUUID());
+//                ((ZombieControl) subscription3).addResult("getId", UUID.randomUUID());
+//                ((ZombieControl) subscription4).addResult("getId", UUID.randomUUID());
+//         
+//              //  bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();
+//                CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
+//                ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog() {
+//
+//                    @Override
+//                    public void setOverdueRules() {
+//                         OverdueRules overdueRules = new MockOverdueRules().setOverdueStatesBundle(bundleODS);                       
+//                        setOverdueRules(overdueRules);  
+//                    }
+//                    
+//                });
+//                bind(CatalogService.class).toInstance(catalogService);
+//                               
+//               
+//                bind(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
+//                bind(OverdueAccessApi.class).toInstance(overdueAccessApi);              
+//                              
+//            }
+//            
+//        });
+//        odc = i.getInstance(OverdueEventCalculator.class);
+//
+//    }
+//
+//    @Test
+//    // S1-S2-S3 subscriptions in B1
+//    // B1 -----[--------]
+//    // S1 --A-------------------------------------
+//    // S2 --B------C------------------------------
+//    // S3 ------------------D---------------------
+//    
+//
+//    //Result
+//    // S1 --A--[-------]--------------------------
+//    // S2 --B--[-------]--------------------------
+//    // S3 ------------------D---------------------
+//    
+//    public void testInsertOverdueEvents() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        BillingEvent A = createRealEvent(now.minusDays(1).minusHours(1), subscription1);
+//        BillingEvent B = createRealEvent(now.minusDays(1), subscription2);
+//        BillingEvent C = createRealEvent(now.plusDays(1), subscription2);
+//        BillingEvent D = createRealEvent(now.plusDays(3), subscription3);
+//        billingEvents.add(A);
+//        billingEvents.add(B);
+//        billingEvents.add(C);
+//        billingEvents.add(D);
+//
+//        SortedSet<OverdueEvent> overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(bundleId1,DISABLED_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now));
+//        overdueBundleEvents.add(new OverdueEvent(bundleId1,CLEAR_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now.plusDays(2)));
+//        
+//        ((ZombieControl)overdueAccessApi).addResult("getOverdueHistory", overdueBundleEvents);
+//        
+//        
+//        odc.insertOverdueEvents(billingEvents);
+//        
+//        assertEquals(billingEvents.size(), 7);
+//        
+//        SortedSet<BillingEvent> s1Events = odc.filter(billingEvents, subscription1);
+//        Iterator<BillingEvent> it1 = s1Events.iterator();
+//        assertEquals(it1.next(), A);
+//        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//        
+//        SortedSet<BillingEvent> s2Events = odc.filter(billingEvents, subscription2);
+//        Iterator<BillingEvent> it2 = s2Events.iterator();       
+//        assertEquals(it2.next(), B);
+//        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//                
+//        SortedSet<BillingEvent> s3Events = odc.filter(billingEvents, subscription3);
+//        Iterator<BillingEvent> it3 = s3Events.iterator();       
+//        assertEquals(it3.next(),D);
+//    }
+//
+//    // Open ended duration with a previous event
+//    // --X--[----------------------------------
+//   @Test
+//    public void testEventsToRemoveOpenPrev() {
+//       DateTime now = clock.getUTCNow();
+//       List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//       SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//       
+//       disabledDuration.add(new DisabledDuration(now, null));
+//       billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//       
+//       SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//       
+//       assertEquals(results.size(), 0);
+//   }
+//
+//   // Open with previous and following events
+//   // --X--[----Y-----------------------------
+//    @Test
+//    public void testEventsToRemoveOpenPrevFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
+//        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
+//        billingEvents.add(e1);
+//        billingEvents.add(e2);
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e2);
+//    }
+//
+//    // Open with no previous event (only following)
+//    // -----[----X-----------------------------
+//    @Test
+//    public void testEventsToRemoveOpenFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        BillingEvent e1  = createRealEvent(now.plusDays(1), subscription1);
+//        billingEvents.add(e1);
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e1);
+//   }
+//
+//    // Closed duration with a single previous event
+//    // --X--[------------]---------------------
+//        @Test
+//    public void testEventsToRemoveClosedPrev() {
+//            DateTime now = clock.getUTCNow();
+//            List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//            SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//            
+//            disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//            BillingEvent e1  = createRealEvent(now.minusDays(1), subscription1);
+//            billingEvents.add(e1);
+//            
+//            SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
+//            
+//            assertEquals(results.size(), 0);
+//    }
+//
+//    // Closed duration with a previous event and in-between event
+//    // --X--[------Y-----]---------------------
+//    @Test
+//    public void testEventsToRemoveClosedPrevBetw() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 2);
+//        assertEquals(results.first().getEffectiveDate(), now);
+//        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed duration with a previous event and in-between event and following
+//    // --X--[------Y-----]-------Z-------------
+//    @Test
+//    public void testEventsToRemoveClosedPrevBetwNext() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
+//        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
+//        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
+//        billingEvents.add(e1);
+//        billingEvents.add(e2);        
+//        billingEvents.add(e3);        
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e2);
+//   }
+//
+//    // Closed with no previous event but in-between events
+//    // -----[------Y-----]---------------------
+//    @Test
+//    public void testEventsToRemoveClosedBetwn() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
+//        billingEvents.add(e2);        
+//      
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e2);
+//    }
+//
+//    // Closed with no previous event but in-between events and following
+//    // -----[------Y-----]-------Z-------------
+//    @Test
+//    public void testEventsToRemoveClosedBetweenFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//
+//        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
+//        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
+//        billingEvents.add(e2);        
+//        billingEvents.add(e3);        
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e2);
+//    }
+//
+//    // Closed duration with only following
+//    // -----[------------]-------Z-------------
+//    @Test
+//    public void testEventsToRemoveClosedFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//
+//        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
+//       
+//        billingEvents.add(e3);        
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 0);
+//     }
+//    
+//    // Open ended duration with a previous event
+//    // --X--[----------------------------------
+//   @Test
+//    public void testCreateNewEventsOpenPrev() {
+//       DateTime now = clock.getUTCNow();
+//       List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//       SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//       
+//       disabledDuration.add(new DisabledDuration(now, null));
+//       billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//       
+//       SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//       
+//       assertEquals(results.size(), 1);
+//       assertEquals(results.first().getEffectiveDate(), now);
+//       assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//       assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//   }
+//
+//   // Open with previous and following events
+//   // --X--[----Y-----------------------------
+//    @Test
+//    public void testCreateNewEventsOpenPrevFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first().getEffectiveDate(), now);
+//        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//    }
+//
+//    // Open with no previous event (only following)
+//    // -----[----X-----------------------------
+//    @Test
+//    public void testCreateNewEventsOpenFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 0);
+//   }
+//
+//    // Closed duration with a single previous event
+//    // --X--[------------]---------------------
+//        @Test
+//    public void testCreateNewEventsClosedPrev() {
+//            DateTime now = clock.getUTCNow();
+//            List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//            SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//            
+//            disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//            billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//            
+//            SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//            
+//            assertEquals(results.size(), 2);
+//            assertEquals(results.first().getEffectiveDate(), now);
+//            assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//            assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//            assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//            assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//            assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed duration with a previous event and in-between event
+//    // --X--[------Y-----]---------------------
+//    @Test
+//    public void testCreateNewEventsClosedPrevBetw() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 2);
+//        assertEquals(results.first().getEffectiveDate(), now);
+//        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed duration with a previous event and in-between event and following
+//    // --X--[------Y-----]-------Z-------------
+//    @Test
+//    public void testCreateNewEventsClosedPrevBetwNext() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 2);
+//        assertEquals(results.first().getEffectiveDate(), now);
+//        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//   }
+//
+//    // Closed with no previous event but in-between events
+//    // -----[------Y-----]---------------------
+//    @Test
+//    public void testCreateNewEventsClosedBetwn() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed with no previous event but in-between events and following
+//    // -----[------Y-----]-------Z-------------
+//    @Test
+//    public void testCreateNewEventsClosedBetweenFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed duration with only following
+//    // -----[------------]-------Z-------------
+//    @Test
+//    public void testCreateNewEventsClosedFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 0);
+//     }
+//
+//    @Test
+//    public void testPrecedingBillingEventForSubscription() {
+//        DateTime now = new DateTime();
+//        
+//        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+//
+//        events.add(createRealEvent(now.minusDays(10), subscription1));
+//        events.add(createRealEvent(now.minusDays(6), subscription1));
+//        events.add(createRealEvent(now.minusDays(5), subscription1));
+//        events.add(createRealEvent(now.minusDays(1), subscription1));
+//        
+//        BillingEvent minus11 = odc.precedingBillingEventForSubscription(now.minusDays(11), events, subscription1);
+//        assertNull(minus11);
+//        
+//        BillingEvent minus5andAHalf= odc.precedingBillingEventForSubscription(now.minusDays(5).minusHours(12), events, subscription1);
+//        assertNotNull(minus5andAHalf);
+//        assertEquals(minus5andAHalf.getEffectiveDate(), now.minusDays(6));
+//      
+//        
+//    }
+//    
+//    protected BillingEvent createRealEvent(DateTime effectiveDate, Subscription subscription) {
+//        final Account account = this.account;
+//        final int billCycleDay = 1;
+//        final PlanPhase planPhase = new MockPlanPhase();
+//        final Plan plan = new MockPlan();
+//        final BigDecimal fixedPrice = BigDecimal.TEN;
+//        final BigDecimal recurringPrice = BigDecimal.TEN;
+//        final Currency currency = Currency.USD;
+//        final String description = "";
+//        final BillingModeType billingModeType = BillingModeType.IN_ADVANCE;
+//        final BillingPeriod billingPeriod = BillingPeriod.MONTHLY;
+//        final SubscriptionTransitionType type = SubscriptionTransitionType.CHANGE;
+//        final Long totalOrdering = 0L; //TODO
+//
+//        return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
+//                fixedPrice, recurringPrice, currency,
+//                billingPeriod, billCycleDay, billingModeType,
+//                description, totalOrdering, type);
+//    }
+//
+//
+//    @Test
+//    public void testFilter() {
+//        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+//        
+//        events.add(createBillingEvent(subscription1));
+//        events.add(createBillingEvent(subscription1));
+//        events.add(createBillingEvent(subscription1));
+//        events.add(createBillingEvent(subscription2));
+//        
+//        SortedSet<BillingEvent> result1 = odc.filter(events, subscription1);
+//        SortedSet<BillingEvent> result2 = odc.filter(events, subscription2);
+//        SortedSet<BillingEvent> result3 = odc.filter(events, subscription3);
+//        
+//        assertEquals(result1.size(), 3);
+//        assertEquals(result1.first().getSubscription(), subscription1);
+//        assertEquals(result1.last().getSubscription(), subscription1);
+//        assertEquals(result2.size(), 1);
+//        assertEquals(result2.first().getSubscription(), subscription2);
+//        assertEquals(result3.size(), 0);
+//    }
+//
+//    @Test
+//    public void testCreateNewDisableEvent() {
+//        DateTime now = clock.getUTCNow();
+//        BillingEvent event = new MockBillingEvent();
+//        
+//        BillingEvent result = odc.createNewDisableEvent(now, event);
+//        assertEquals(result.getBillCycleDay(),event.getBillCycleDay());
+//        assertEquals(result.getEffectiveDate(), now);
+//        assertEquals(result.getPlanPhase(), event.getPlanPhase());
+//        assertEquals(result.getPlan(), event.getPlan());
+//        assertEquals(result.getFixedPrice(),BigDecimal.ZERO);
+//        assertEquals(result.getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(result.getCurrency(), event.getCurrency());
+//        assertEquals(result.getDescription(), "");
+//        assertEquals(result.getBillingMode(), event.getBillingMode());
+//        assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
+//        assertEquals(result.getTransitionType(),  SubscriptionTransitionType.CANCEL);
+//        assertEquals(result.getTotalOrdering(), new Long(0));
+//    }
+//
+//    @Test
+//    public void testCreateNewReenableEvent() {
+//        DateTime now = clock.getUTCNow();
+//        BillingEvent event = new MockBillingEvent();
+//        
+//        BillingEvent result = odc.createNewReenableEvent(now, event);
+//        assertEquals(result.getBillCycleDay(),event.getBillCycleDay());
+//        assertEquals(result.getEffectiveDate(), now);
+//        assertEquals(result.getPlanPhase(), event.getPlanPhase());
+//        assertEquals(result.getPlan(), event.getPlan());
+//        assertEquals(result.getFixedPrice(),event.getFixedPrice());
+//        assertEquals(result.getRecurringPrice(), event.getRecurringPrice());
+//        assertEquals(result.getCurrency(), event.getCurrency());
+//        assertEquals(result.getDescription(), "");
+//        assertEquals(result.getBillingMode(), event.getBillingMode());
+//        assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
+//        assertEquals(result.getTransitionType(),  SubscriptionTransitionType.RE_CREATE);
+//        assertEquals(result.getTotalOrdering(), new Long(0));
+//    }
+//    
+//    private class MockBillingEvent extends DefaultBillingEvent {
+//        public MockBillingEvent() {
+//            super(account, subscription1, clock.getUTCNow(), null, null, BigDecimal.ZERO, BigDecimal.TEN, Currency.USD, BillingPeriod.ANNUAL,
+//                    4, BillingModeType.IN_ADVANCE, "", 3L, SubscriptionTransitionType.CREATE);
+//        }        
+//    }
+//
+//    @Test
+//    public void testCreateBundleSubscriptionMap() {
+//        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+//        events.add(createBillingEvent(subscription1));
+//        events.add(createBillingEvent(subscription2));
+//        events.add(createBillingEvent(subscription3));
+//        events.add(createBillingEvent(subscription4));
+//        
+//        Hashtable<UUID,Set<Subscription>> map = odc.createBundleSubscriptionMap(events);
+//        
+//        assertNotNull(map);
+//        assertEquals(map.keySet().size(),2);
+//        assertEquals(map.get(bundleId1).size(), 3);
+//        assertEquals(map.get(bundleId2).size(), 1);
+//        
+//    }
+//
+//    private BillingEvent createBillingEvent(Subscription subscription) {
+//        BillingEvent result =  BrainDeadProxyFactory.createBrainDeadProxyFor(BillingEvent.class, Comparable.class);
+//        ((ZombieControl)result).addResult("getSubscription", subscription);
+//        ((ZombieControl)result).addResult("compareTo", 1);
+//        return result;
+//    }
+//
+//    @Test
+//    public void testCreateDisablePairs() {
+//        SortedSet<OverdueEvent> overdueBundleEvents;
+//        UUID ovdId = UUID.randomUUID();
+//        DateTime now = clock.getUTCNow();
+//        
+//        //simple events open clear -> disabled
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        
+//        List<DisabledDuration> pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNull(pairs.get(0).getEnd());
+//        
+//        //simple events closed clear -> disabled
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+//        
+//        pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNotNull(pairs.get(0).getEnd());
+//        assertEquals(pairs.get(0).getEnd(),now.plusDays(2));
+//
+//        //simple BUNDLE events closed clear -> disabled
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+//        
+//        pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNotNull(pairs.get(0).getEnd());
+//        assertEquals(pairs.get(0).getEnd(),now.plusDays(2));
+//        
+//        
+//        //two or more disableds in a row
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(3)));
+//        
+//        pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNotNull(pairs.get(0).getEnd());
+//        assertEquals(pairs.get(0).getEnd(),now.plusDays(3));
+//
+//       
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(3)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(4)));
+//        
+//        pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNotNull(pairs.get(0).getEnd());
+//        assertEquals(pairs.get(0).getEnd(),now.plusDays(4));
+//  
+//    }
+//
+//    @Test
+//    public void testIsDisableEvent() {
+//       DateTime now = clock.getUTCNow();
+//           assertTrue(!odc.isDisableEvent(new OverdueEvent(new UUID(0L,0L), CLEAR_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now)));
+//       assertTrue(odc.isDisableEvent(new OverdueEvent(new UUID(0L,0L), DISABLED_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now)));
+//    }
+//
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
index c7e155d..6ea53bc 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
@@ -22,7 +22,6 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 
 @Test(groups = "fast")
 public class TestMigrationMemory extends TestMigration {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
index 67b0371..587ca46 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
@@ -22,7 +22,6 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 
 @Test(groups = "slow")
 public class TestMigrationSql extends TestMigration {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
index c78ee3c..20409ee 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
@@ -63,7 +63,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.engine.core.Engine;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.engine.dao.MockEntitlementDao;
@@ -129,7 +129,6 @@ public abstract class TestApiBase {
         } catch (Exception e) {
             log.warn("Failed to tearDown test properly ", e);
         }
-        //if(helper != null) { helper.stopMysql(); }
     }
 
     @BeforeClass(alwaysRun = true)
@@ -428,8 +427,8 @@ public abstract class TestApiBase {
         }
     }
 
-    protected void printSubscriptionTransitions(List<SubscriptionTransition> transitions) {
-        for (SubscriptionTransition cur : transitions) {
+    protected void printSubscriptionTransitions(List<SubscriptionEventTransition> transitions) {
+        for (SubscriptionEventTransition cur : transitions) {
             log.debug("Transition " + cur);
         }
     }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index 0d1d446..f18979c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -38,11 +38,10 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.clock.DefaultClock;
 
 public class TestUserApiAddOn extends TestApiBase {
@@ -339,7 +338,7 @@ public class TestUserApiAddOn extends TestApiBase {
            assertEquals(aoSubscription.getBundleStartDate(), baseSubscription.getBundleStartDate());
 
            // CHECK next AO PHASE EVENT IS INDEED A MONTH AFTER BP STARTED => BUNDLE ALIGNMENT
-           SubscriptionTransition aoPendingTranstion = aoSubscription.getPendingTransition();
+           SubscriptionEventTransition aoPendingTranstion = aoSubscription.getPendingTransition();
 
            if (expAlignement == PlanAlignmentCreate.START_OF_BUNDLE) {
                assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), baseSubscription.getStartDate().plusMonths(1));
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
index 55ad5e8..5a7d33e 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
@@ -17,25 +17,23 @@
 package com.ning.billing.entitlement.api.user;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.assertFalse;
 
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
-import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
-import com.ning.billing.util.clock.DefaultClock;
 import org.joda.time.DateTime;
 import org.testng.Assert;
 
-
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
 import com.ning.billing.entitlement.api.TestApiBase;
-import java.util.List;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
+import com.ning.billing.util.clock.DefaultClock;
 
 public abstract class TestUserApiCancel extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
index 5162f17..7eccbdd 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
@@ -16,14 +16,13 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
-
-import org.testng.annotations.Test;
 
 public class TestUserApiCancelMemory extends TestUserApiCancel {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
index bdf02e7..6d02736 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
@@ -16,14 +16,13 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
-
-import org.testng.annotations.Test;
 
 public class TestUserApiCancelSql extends TestUserApiCancel {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
index f7f8c41..98e495d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
@@ -29,14 +29,13 @@ import org.testng.Assert;
 
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
-
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.user.ApiEvent;
@@ -467,7 +466,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
 
             DateTime expectedNextPhaseDate =  subscription.getStartDate().plusDays(30).plusMonths(6);
-            SubscriptionTransition nextPhase = subscription.getPendingTransition();
+            SubscriptionEventTransition nextPhase = subscription.getPendingTransition();
             DateTime nextPhaseEffectiveDate = nextPhase.getEffectiveTransitionTime();
 
             assertEquals(nextPhaseEffectiveDate, expectedNextPhaseDate);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
index 7ec661c..8bbdd2d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
@@ -16,14 +16,13 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
-
-import org.testng.annotations.Test;
 
 public class TestUserApiChangePlanMemory extends TestUserApiChangePlan {
 
@@ -63,14 +62,6 @@ public class TestUserApiChangePlanMemory extends TestUserApiChangePlan {
         super.testMultipleChangeLastEOT();
     }
 
-    /*
-    // Set to false until we implement rescue example.
-    @Override
-    @Test(enabled=false, groups={"fast"})
-    public void testChangePlanChangePlanAlignEOTWithChargeThroughDate() throws EntitlementBillingApiException {
-        super.testChangePlanChangePlanAlignEOTWithChargeThroughDate();
-    }
-    */
 
     @Override
     @Test(enabled=true, groups={"fast-disabled"})
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
index 0396f35..509b056 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
@@ -16,14 +16,13 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
-
-import org.testng.annotations.Test;
 
 public class TestUserApiChangePlanSql extends TestUserApiChangePlan {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
index a8d6e0c..01ced07 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
@@ -22,19 +22,20 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 
 import java.util.List;
+
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 
 import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
 import com.ning.billing.util.clock.DefaultClock;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
index 922de5e..7987d87 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
@@ -16,13 +16,12 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
-
-import org.testng.annotations.Test;
 
 public class TestUserApiCreateMemory extends TestUserApiCreate {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
index e5dcc11..c890da7 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
@@ -16,13 +16,12 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
-
-import org.testng.annotations.Test;
 
 public class TestUserApiCreateSql extends TestUserApiCreate {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
index 23e6a6e..b21764d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
@@ -16,31 +16,33 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
-
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
-import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
-
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
 import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-import static org.testng.Assert.*;
 
 public class TestUserApiDemos extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
index 3ec6da1..440b780 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
@@ -16,6 +16,18 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
@@ -24,21 +36,10 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import javax.annotation.Nullable;
-import java.util.UUID;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
 
 public class TestUserApiError extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
index 7dbc802..91aaf02 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
@@ -25,11 +25,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 
-import com.google.inject.Injector;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 
 public abstract class TestUserApiRecreate extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
index fc7de36..b6f97c1 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
@@ -22,7 +22,6 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 
 public class TestUserApiRecreateMemory extends TestUserApiRecreate {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
index 0202753..2c1db68 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
@@ -22,7 +22,6 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 
 public class TestUserApiRecreateSql extends TestUserApiRecreate {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
index 80eafc9..08f1ac1 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
@@ -16,6 +16,14 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
@@ -23,18 +31,11 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhase;
-
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
 import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
 
 public class TestUserApiScenarios extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
index 3e2d52f..afc5591 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
@@ -16,17 +16,11 @@
 
 package com.ning.billing.entitlement.api.user;
 
-import java.util.List;
-
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.clock.DefaultClock;
+import java.util.List;
+
 import org.joda.time.DateTime;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -36,9 +30,14 @@ import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.DefaultClock;
 import com.ning.billing.util.customfield.CustomField;
 
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserToken.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserToken.java
new file mode 100644
index 0000000..08f8aa4
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserToken.java
@@ -0,0 +1,46 @@
+/* 
+ * Copyright 2010-2011 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.entitlement.api.user;
+
+import org.testng.annotations.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Stage;
+import com.ning.billing.entitlement.api.TestApiBase;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
+import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+
+public class TestUserToken extends TestApiBase {
+
+
+    @Override
+    public Injector getInjector() {
+        return Guice.createInjector(Stage.DEVELOPMENT, new MockEngineModuleSql());
+    }
+
+    @Test(enabled= true, groups={"slow"})
+    public void testFoo() throws EntitlementBillingApiException {
+
+        
+        /*for (int i = 0; i < MAX_STRESS_ITERATIONS; i++) {
+            cleanupTest();
+            setupTest();
+            testCancelSubscriptionIMM();
+        }*/
+
+    }
+}
\ No newline at end of file
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementNotificationKey.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementNotificationKey.java
new file mode 100644
index 0000000..dbd7098
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementNotificationKey.java
@@ -0,0 +1,45 @@
+/* 
+ * Copyright 2010-2011 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.entitlement.engine.core;
+
+import java.util.UUID;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestEntitlementNotificationKey {
+
+	@Test(groups="fast")
+	public void testKeyWithSeqId() {
+		UUID id = UUID.randomUUID();
+		int seq = 4;
+		EntitlementNotificationKey input = new EntitlementNotificationKey(id, seq);
+		Assert.assertEquals(id.toString() + ":" + seq, input.toString());
+		EntitlementNotificationKey output = new EntitlementNotificationKey(input.toString());
+		Assert.assertEquals(output, input);
+	}
+
+	@Test(groups="fast")
+	public void testKeyWithoutSeqId() {
+		UUID id = UUID.randomUUID();
+		int seq = 0;
+		EntitlementNotificationKey input = new EntitlementNotificationKey(id, seq);
+		Assert.assertEquals(input.toString(), id.toString());
+		EntitlementNotificationKey output = new EntitlementNotificationKey(input.toString());
+		Assert.assertEquals(output, input);
+	}
+
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
index 94836a8..5bb0fb5 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
@@ -24,7 +24,6 @@ import java.util.List;
 import java.util.TreeSet;
 import java.util.UUID;
 
-import com.ning.billing.util.callcontext.CallContext;
 import org.apache.commons.lang.NotImplementedException;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
@@ -50,6 +49,7 @@ import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.user.ApiEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
+import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.notificationq.NotificationKey;
 import com.ning.billing.util.notificationq.NotificationQueue;
@@ -282,7 +282,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
 
     @Override
     public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent,
-                                   final CallContext context) {
+                                   final CallContext context, final int seqId) {
         synchronized (cancelEvent) {
             cancelNextPhaseEvent(subscriptionId);
             insertEvent(cancelEvent);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
index 54d0e34..8deaef6 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
@@ -16,8 +16,6 @@
 
 package com.ning.billing.entitlement.engine.dao;
 
-import com.ning.billing.util.customfield.dao.CustomFieldDao;
-import com.ning.billing.util.tag.dao.TagDao;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.Transaction;
 import org.skife.jdbi.v2.TransactionStatus;
@@ -27,11 +25,10 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
 import com.google.inject.Inject;
 import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.entitlement.api.user.SubscriptionFactory;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.customfield.dao.CustomFieldDao;
 import com.ning.billing.util.notificationq.NotificationQueueService;
-import com.ning.billing.util.overdue.OverdueAccessApi;
 
 public class MockEntitlementDaoSql extends EntitlementSqlDao implements MockEntitlementDao {
 
@@ -39,9 +36,9 @@ public class MockEntitlementDaoSql extends EntitlementSqlDao implements MockEnti
 
     @Inject
     public MockEntitlementDaoSql(IDBI dbi, Clock clock, AddonUtils addonUtils, NotificationQueueService notificationQueueService,
-                                 CustomFieldDao customFieldDao, final OverdueAccessApi overdueApi,
+                                 CustomFieldDao customFieldDao, 
                                  final CatalogService catalogService) {
-        super(dbi, clock, addonUtils, notificationQueueService, customFieldDao, overdueApi, catalogService);
+        super(dbi, clock, addonUtils, notificationQueueService, customFieldDao, catalogService);
         this.resetDao = dbi.onDemand(ResetSqlDao.class);
     }
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
index 9b5a593..c795ca5 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
@@ -18,21 +18,14 @@ package com.ning.billing.entitlement.glue;
 
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.catalog.glue.CatalogModule;
-import com.ning.billing.entitlement.api.overdue.MockOverdueChecker;
-import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 import com.ning.billing.mock.BrainDeadProxyFactory;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.clock.MockClockModule;
 import com.ning.billing.util.glue.BusModule;
 import com.ning.billing.util.glue.CallContextModule;
 
 public class MockEngineModule extends EntitlementModule {
 
-    
-    protected void installOverdueChecker() {
-        bind(OverdueChecker.class).to(MockOverdueChecker.class).asEagerSingleton();       
-    }
-
+   
     @Override
     protected void configure() {
         super.configure();
@@ -41,6 +34,5 @@ public class MockEngineModule extends EntitlementModule {
         bind(AccountUserApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class));
         install(new MockClockModule());
         install(new CallContextModule());
-        install(new MockOverdueAccessModule());
     }
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
index f774e58..a1744ca 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
@@ -16,19 +16,17 @@
 
 package com.ning.billing.entitlement.glue;
 
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.IDBI;
+
 import com.ning.billing.dbi.DBIProvider;
 import com.ning.billing.dbi.DbiConfig;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.engine.dao.MockEntitlementDaoSql;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.glue.FieldStoreModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 
-import org.skife.config.ConfigurationObjectFactory;
-import org.skife.jdbi.v2.IDBI;
-
 public class MockEngineModuleSql extends MockEngineModule {
 
 
diff --git a/entitlement/src/test/resources/testInput.xml b/entitlement/src/test/resources/testInput.xml
index 6d761e0..8a97d57 100644
--- a/entitlement/src/test/resources/testInput.xml
+++ b/entitlement/src/test/resources/testInput.xml
@@ -171,14 +171,6 @@ Use Cases to do:
 		</priceList>
 	</rules>
 
-    <overdueRules> 
-      <bundleOverdueStates>
-           <state name="Clear">
-               <isClearState>true</isClearState>
-           </state> 
-       </bundleOverdueStates>
-    </overdueRules>
-
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>

index.html 120(+120 -0)

diff --git a/index.html b/index.html
new file mode 100644
index 0000000..f907b08
--- /dev/null
+++ b/index.html
@@ -0,0 +1,120 @@
+<!-- ~ Copyright 2010-2011 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. -->
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>Killbill: Subscription Management/Billing System</title>
+    <meta name="description" content="Killbill is a new open source subscription management/billing system">
+    <meta name="author" content="Stephane Brossier">
+
+    <!--[if lt IE 9]>
+    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
+    <![endif]-->
+
+    <link rel=stylesheet type="text/css" href="doc/css/bootstrap.min.css">
+    <link rel=stylesheet type="text/css" href="doc/css/prettify.css">
+    <link rel=stylesheet type="text/css" href="doc/css/killbill.css">
+    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+    <script src="js/prettify.js"></script>
+    <script src="js/bootstrap-dropdown.js"></script>
+
+    <script type="text/javascript">
+      var _gaq = _gaq || [];
+      _gaq.push(['_setAccount', 'UA-19297396-1']);
+      _gaq.push(['_trackPageview']);
+      (function() {
+        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+      })();
+    </script>
+</head>
+
+<body>
+
+<div class="topbar" data-dropdown="dropdown">
+    <div class="topbar-inner">
+        <div class="container-fluid">
+            <a class="brand" href="index.html">Killbill</a>
+            <ul class="nav">
+                <li><a href="doc/user.html">User Guide</a></li>
+                <li><a href="doc/setup.html">Setup/Installation</a></li>
+                <li><a href="doc/api.html">APIs</a></li>
+                <li><a href="doc/design.html">Design</a></li>                                                
+                <li><a href="http://groups.google.com/group/killbill-users">Mailing List</a></li>
+            </ul>
+            <ul class="nav secondary-nav">
+                <li class="dropdown">
+                    <a href="#" class="dropdown-toggle">Maven sites</a>
+                    <ul class="dropdown-menu">
+                        <li><a href="http://sbrossie.github.com/killbill" target="_blank">Killbill</a></li>
+                    </ul>
+                </li>
+            </ul>
+            <ul class="nav secondary-nav">
+                <li class="dropdown">
+                    <a href="#" class="dropdown-toggle">Github projects</a>
+                    <ul class="dropdown-menu">
+                        <li><a href="http://github.com/ning/killbill" target="_blank">Killbill</a></li>
+                    </ul>
+                </li>
+            </ul>
+        </div>
+    </div>
+</div>
+
+
+<div class="container-fluid">
+    <div class="sidebar">
+        <div class="well">
+            <h5>Quick Presentation</h5>
+            <ul>
+                <li><a href="#motivation">Motivation</a></li>
+                <li><a href="#overview">Overview</a></li>
+                <li><a href="#goals">Goals</a></li>
+                <li><a href="#feature-list">Feature List</a></li>
+                <li><a href="#dependencies">Dependencies</a></li>
+                <li><a href="#state-project">State of the Project</a></li>
+            </ul>
+        </div>
+    </div>
+
+    <div class="content">
+
+        <h2 id="motivation">Motivation</h2>
+    
+            This is the motivation; why we are building it
+
+        <h2 id="overview">Overview</h2>
+    
+            This is the overview; describes what it does / (does not ?)
+
+
+        <h2 id="goals">Goals</h2>
+
+            This is the goals
+
+       <h2 id="feature-list">Feature List</h2>
+
+            This is the feature list
+
+       <h2 id="dependencies">Dependencies</h2>
+
+            This is the dependencies
+            
+        <h2 id="state-project">State of the Project</h2>
+
+            This is the state of the project
+            
+    </div>
+</div>
+</body>
+</html>
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultEmptyInvoiceNotification.java b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultEmptyInvoiceNotification.java
new file mode 100644
index 0000000..5d57b2c
--- /dev/null
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultEmptyInvoiceNotification.java
@@ -0,0 +1,56 @@
+/* 
+ * Copyright 2010-2011 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.invoice.api.user;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.invoice.api.EmptyInvoiceEvent;
+
+public class DefaultEmptyInvoiceNotification implements EmptyInvoiceEvent {
+
+    private final UUID accountId;
+    private final DateTime processingDate;
+    private final UUID userToken;
+
+    
+    public DefaultEmptyInvoiceNotification(final UUID accountId,
+            final DateTime processingDate, final UUID userToken) {
+        super();
+        this.accountId = accountId;
+        this.processingDate = processingDate;
+        this.userToken = userToken;
+    }
+
+    @Override
+    public BusEventType getBusEventType() {
+        return BusEventType.INVOICE_EMPTY;
+    }
+
+    @Override
+    public UUID getUserToken() {
+        return userToken;
+    }
+
+    public UUID getAccountId() {
+        return accountId;
+    }
+
+    public DateTime getProcessingDate() {
+        return processingDate;
+    }
+}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceCreationNotification.java b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceCreationNotification.java
index 5c6785c..815ce51 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceCreationNotification.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceCreationNotification.java
@@ -22,23 +22,37 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.invoice.api.InvoiceCreationNotification;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.util.bus.BusEvent.BusEventType;
 
-public class DefaultInvoiceCreationNotification implements InvoiceCreationNotification {
+public class DefaultInvoiceCreationNotification implements InvoiceCreationEvent {
+	
     private final UUID invoiceId;
     private final UUID accountId;
     private final BigDecimal amountOwed;
     private final Currency currency;
     private final DateTime invoiceCreationDate;
+    private final UUID userToken;
 
-    public DefaultInvoiceCreationNotification(UUID invoiceId, UUID accountId, BigDecimal amountOwed, Currency currency, DateTime invoiceCreationDate) {
+    public DefaultInvoiceCreationNotification(UUID invoiceId, UUID accountId, BigDecimal amountOwed, Currency currency, DateTime invoiceCreationDate, UUID userToken) {
         this.invoiceId = invoiceId;
         this.accountId = accountId;
         this.amountOwed = amountOwed;
         this.currency = currency;
         this.invoiceCreationDate = invoiceCreationDate;
+        this.userToken = userToken;
     }
 
+	@Override
+	public BusEventType getBusEventType() {
+		return BusEventType.INVOICE_CREATION;
+	}
+
+	@Override
+	public UUID getUserToken() {
+		return userToken;
+	}
+
     @Override
     public UUID getInvoiceId() {
         return invoiceId;
@@ -68,5 +82,4 @@ public class DefaultInvoiceCreationNotification implements InvoiceCreationNotifi
     public String toString() {
         return "DefaultInvoiceCreationNotification [invoiceId=" + invoiceId + ", accountId=" + accountId + ", amountOwed=" + amountOwed + ", currency=" + currency + ", invoiceCreationDate=" + invoiceCreationDate + "]";
     }
-
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index e51ec58..f6ba4a5 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -43,7 +43,7 @@ import org.slf4j.LoggerFactory;
 import com.google.inject.Inject;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.api.InvoiceCreationNotification;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.invoice.api.user.DefaultInvoiceCreationNotification;
@@ -191,10 +191,11 @@ public class DefaultInvoiceDao implements InvoiceDao {
         });
 
         // TODO: move this inside the transaction once the bus is persistent
-        InvoiceCreationNotification event;
+        InvoiceCreationEvent event;
         event = new DefaultInvoiceCreationNotification(invoice.getId(), invoice.getAccountId(),
                                                       invoice.getBalance(), invoice.getCurrency(),
-                                                      invoice.getInvoiceDate());
+                                                      invoice.getInvoiceDate(),
+                                                      context.getUserToken());
         try {
             eventBus.post(event);
         } catch (Bus.EventBusException e) {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
index bb8d957..043c670 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -21,7 +21,12 @@ import java.util.List;
 import java.util.SortedSet;
 import java.util.UUID;
 
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.Bus.EventBusException;
+import com.ning.billing.util.bus.BusEvent;
 import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.clock.Clock;
+
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,10 +38,11 @@ import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.entitlement.api.billing.BillingEvent;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.user.DefaultEmptyInvoiceNotification;
 import com.ning.billing.invoice.dao.InvoiceDao;
 import com.ning.billing.invoice.model.BillingEventSet;
 import com.ning.billing.invoice.model.InvoiceGenerator;
@@ -54,6 +60,8 @@ public class InvoiceDispatcher {
     private final AccountUserApi accountUserApi;
     private final InvoiceDao invoiceDao;
     private final GlobalLocker locker;
+    private final Bus eventBus;
+    private final Clock clock;
 
     private final boolean VERBOSE_OUTPUT;
 
@@ -61,18 +69,22 @@ public class InvoiceDispatcher {
     public InvoiceDispatcher(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
                              final EntitlementBillingApi entitlementBillingApi,
                              final InvoiceDao invoiceDao,
-                             final GlobalLocker locker) {
+                             final GlobalLocker locker,
+                             final Bus eventBus,
+                             final Clock clock) {
         this.generator = generator;
         this.entitlementBillingApi = entitlementBillingApi;
         this.accountUserApi = accountUserApi;
         this.invoiceDao = invoiceDao;
         this.locker = locker;
+        this.eventBus = eventBus;
+        this.clock = clock;
 
         String verboseOutputValue = System.getProperty("VERBOSE_OUTPUT");
         VERBOSE_OUTPUT = (verboseOutputValue != null) && Boolean.parseBoolean(verboseOutputValue);
     }
 
-    public void processSubscription(final SubscriptionTransition transition,
+    public void processSubscription(final SubscriptionEventTransition transition,
                                     final CallContext context) throws InvoiceApiException {
         UUID subscriptionId = transition.getSubscriptionId();
         DateTime targetDate = transition.getEffectiveTransitionTime();
@@ -118,6 +130,14 @@ public class InvoiceDispatcher {
         return null;
     }
 
+    private void postEmptyInvoiceEvent(final UUID accountId, final UUID userToken) {
+        try {
+            BusEvent event = new DefaultEmptyInvoiceNotification(accountId, clock.getUTCNow(), userToken);
+            eventBus.post(event);
+        } catch (EventBusException e){
+            log.error("Failed to post DefaultEmptyInvoiceNotification event for account {} ", accountId, e);
+        }
+    }
     private Invoice processAccountWithLock(final UUID accountId, final DateTime targetDate,
                                            final boolean dryRun, final CallContext context) throws InvoiceApiException {
 
@@ -125,7 +145,7 @@ public class InvoiceDispatcher {
         if (account == null) {
             log.error("Failed handling entitlement change.",
                     new InvoiceApiException(ErrorCode.INVOICE_ACCOUNT_ID_INVALID, accountId.toString()));
-            return null;
+            return null;    
         }
 
         SortedSet<BillingEvent> events = entitlementBillingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId);
@@ -139,9 +159,11 @@ public class InvoiceDispatcher {
         if (invoice == null) {
             log.info("Generated null invoice.");
             outputDebugData(events, invoices);
+            if (!dryRun) {
+                postEmptyInvoiceEvent(accountId, context.getUserToken());
+            }
         } else {
             log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
-
             if (VERBOSE_OUTPUT) {
                 log.info("New items");
                 for (InvoiceItem item : invoice.getInvoiceItems()) {
@@ -149,12 +171,10 @@ public class InvoiceDispatcher {
                 }
             }
             outputDebugData(events, invoices);
-
-            if (invoice.getNumberOfItems() > 0 && !dryRun) {
+            if (!dryRun) {
                 invoiceDao.create(invoice, context);
             }
         }
-        
         return invoice;
     }
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
index ff23965..b02c3e8 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
@@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.invoice.api.InvoiceApiException;
 
 public class InvoiceListener {
@@ -43,9 +43,13 @@ public class InvoiceListener {
     }
 
     @Subscribe
-    public void handleSubscriptionTransition(final SubscriptionTransition transition) {
+    public void handleSubscriptionTransition(final SubscriptionEventTransition transition) {
         try {
-            CallContext context = factory.createCallContext("Transition", CallOrigin.INTERNAL, UserType.SYSTEM);
+            if (transition.getRemainingEventsForUserOperation() > 0) {
+                // Skip invoice generation as there is more coming...
+                return;
+            }
+            CallContext context = factory.createCallContext("Transition", CallOrigin.INTERNAL, UserType.SYSTEM, transition.getUserToken());
         	dispatcher.processSubscription(transition, context);
         } catch (InvoiceApiException e) {
             log.error(e.getMessage());
diff --git a/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDateNotifier.java b/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDateNotifier.java
index 03dc211..2f6ea8b 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDateNotifier.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDateNotifier.java
@@ -19,19 +19,17 @@ package com.ning.billing.invoice.notification;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 import com.ning.billing.config.InvoiceConfig;
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.invoice.InvoiceListener;
 import com.ning.billing.invoice.api.DefaultInvoiceService;
-import com.ning.billing.util.bus.Bus;
-import com.ning.billing.util.notificationq.NotificationConfig;
-import com.ning.billing.util.notificationq.NotificationKey;
+
 import com.ning.billing.util.notificationq.NotificationQueue;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
@@ -86,7 +84,7 @@ public class DefaultNextBillingDateNotifier implements  NextBillingDateNotifier 
             new NotificationConfig() {
                 @Override
                 public boolean isNotificationProcessingOff() {
-                    return config.isEventProcessingOff();
+                    return config.isNotificationProcessingOff();
                 }
                 @Override
                 public long getNotificationSleepTimeMs() {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index 71be8c5..3aee83d 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -53,7 +53,7 @@ import com.ning.billing.entitlement.api.billing.BillingModeType;
 import com.ning.billing.entitlement.api.billing.DefaultBillingEvent;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.invoice.InvoiceDispatcher;
 import com.ning.billing.invoice.TestInvoiceDispatcher;
 import com.ning.billing.invoice.api.Invoice;
@@ -185,8 +185,7 @@ public class TestDefaultInvoiceMigrationApi {
 
 		EntitlementBillingApi entitlementBillingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementBillingApi.class);
         ((ZombieControl)entitlementBillingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
-        
-		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao, locker);
+		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao, locker, busService.getBus(), clock);
 
         CallContext context = new DefaultCallContextFactory(clock).createCallContext("Migration test", CallOrigin.TEST, UserType.TEST);
 		Invoice invoice = dispatcher.processAccount(accountId, date_regular, true, context);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
index 49d2cb1..fbb77dd 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
@@ -61,7 +61,7 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
         @Override
         public long getNotificationSleepTimeMs() {throw new UnsupportedOperationException();}
         @Override
-        public boolean isEventProcessingOff() {throw new UnsupportedOperationException();}
+        public boolean isNotificationProcessingOff() {throw new UnsupportedOperationException();}
         @Override
         public int getNumberOfMonthsInFuture() {return 36;}
     };
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 2caa37f..a3b8888 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -30,7 +30,7 @@ import com.ning.billing.entitlement.api.billing.BillingEvent;
 import com.ning.billing.entitlement.api.billing.BillingModeType;
 import com.ning.billing.entitlement.api.billing.DefaultBillingEvent;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
index dec7697..c7818d8 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
@@ -52,7 +52,7 @@ public class MockInvoiceDao implements InvoiceDao {
         try {
             eventBus.post(new DefaultInvoiceCreationNotification(invoice.getId(), invoice.getAccountId(),
                                                                  invoice.getBalance(), invoice.getCurrency(),
-                                                                 invoice.getInvoiceDate()));
+                                                                 invoice.getInvoiceDate(), null));
         }
         catch (Bus.EventBusException ex) {
             throw new RuntimeException(ex);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
index fdcab00..368b74f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
@@ -36,7 +36,6 @@ import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
 import com.ning.billing.invoice.notification.NextBillingDateNotifier;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
 import com.ning.billing.mock.BrainDeadProxyFactory;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.callcontext.CallContextFactory;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.clock.Clock;
@@ -103,7 +102,6 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
         bind(AccountUserApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class));
         install(new CatalogModule());
         install(new EntitlementModule());
-        install(new MockOverdueAccessModule());
         install(new GlobalLockerModule());
 
         super.configure();
diff --git a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
index f3d5aaf..c062a06 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
@@ -16,8 +16,6 @@
 
 package com.ning.billing.invoice;
 
-import java.util.UUID;
-
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.jdbi.v2.IDBI;
 
@@ -27,10 +25,6 @@ import com.ning.billing.catalog.glue.CatalogModule;
 import com.ning.billing.dbi.DBIProvider;
 import com.ning.billing.dbi.DbiConfig;
 import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.entitlement.api.overdue.OverdueChecker;
-import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
-import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.glue.EntitlementModule;
 import com.ning.billing.invoice.glue.InvoiceModule;
 import com.ning.billing.mock.BrainDeadProxyFactory;
@@ -80,27 +74,7 @@ public class MockModule extends AbstractModule {
     }
     
     protected void installEntitlementModule() {
-        install(new EntitlementModule() {
-
-            @Override
-            protected void installOverdueChecker() {
-                bind(OverdueChecker.class).toInstance(new OverdueChecker() {
-
-                    @Override
-                    public void checkBlocked(Subscription subscription)
-                            throws EntitlementUserApiException {
-                    }
-
-                    @Override
-                    public void checkBlocked(SubscriptionBundle bundle)
-                            throws EntitlementUserApiException {
-                     }
-
-                            
-                });
-            }
-            
-        });
+        install(new EntitlementModule());
     }
 
     protected void installInvoiceModule() {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
index 6c201b6..e70626f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
@@ -35,6 +35,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
@@ -47,7 +48,6 @@ import com.ning.billing.config.InvoiceConfig;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
-import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
@@ -63,7 +63,6 @@ import com.ning.billing.invoice.model.InvoiceGenerator;
 import com.ning.billing.lifecycle.KillbillService.ServiceException;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.InMemoryBus;
 import com.ning.billing.util.callcontext.CallContextFactory;
@@ -119,10 +118,9 @@ public class TestNextBillingDateNotifier {
 	@BeforeClass(groups={"slow"})
 	public void setup() throws ServiceException, IOException, ClassNotFoundException, SQLException {
 		//TestApiBase.loadSystemPropertiesFromClasspath("/entitlement.properties");
-        final Injector g = Guice.createInjector(Stage.PRODUCTION,  new MockOverdueAccessModule() {
+        final Injector g = Guice.createInjector(Stage.PRODUCTION,  new AbstractModule() {
 			
             protected void configure() {
-                super.configure();
                 bind(Clock.class).to(ClockMock.class).asEagerSingleton();
                 bind(CallContextFactory.class).to(DefaultCallContextFactory.class).asEagerSingleton();
                 bind(Bus.class).to(InMemoryBus.class).asEagerSingleton();
@@ -146,16 +144,7 @@ public class TestNextBillingDateNotifier {
                 bind(AccountUserApi.class).to(MockAccountUserApi.class).asEagerSingleton();
                 bind(EntitlementBillingApi.class).to(DefaultEntitlementBillingApi.class).asEagerSingleton();
                 bind(EntitlementUserApi.class).to(DefaultEntitlementUserApi.class).asEagerSingleton();
-                bind(OverdueChecker.class).toInstance(new OverdueChecker() {
-
-                    @Override
-                    public void checkBlocked(Subscription subscription){}
-
-                    @Override
-                    public void checkBlocked(SubscriptionBundle bundle){}
-                                           
-                });
-			}
+            }
         });
 
         clock = g.getInstance(Clock.class);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
index 2e57eea..45f1db4 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -48,7 +48,7 @@ import com.ning.billing.entitlement.api.billing.BillingModeType;
 import com.ning.billing.entitlement.api.billing.DefaultBillingEvent;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.dao.InvoiceDao;
@@ -56,7 +56,6 @@ import com.ning.billing.invoice.model.InvoiceGenerator;
 import com.ning.billing.invoice.notification.NextBillingDateNotifier;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
-import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.bus.BusService;
 import com.ning.billing.util.bus.DefaultBusService;
 import com.ning.billing.util.callcontext.CallContext;
@@ -67,7 +66,7 @@ import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.globallocker.GlobalLocker;
 
 @Test(groups = "slow")
-@Guice(modules = {MockModule.class, MockOverdueAccessModule.class})
+@Guice(modules = {MockModule.class})
 public class TestInvoiceDispatcher {
 	private Logger log = LoggerFactory.getLogger(TestInvoiceDispatcher.class);
 
@@ -155,7 +154,7 @@ public class TestInvoiceDispatcher {
 
 		DateTime target = new DateTime();
 
-		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao, locker);
+		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao, locker, busService.getBus(), clock);
 
 		Invoice invoice = dispatcher.processAccount(accountId, target, true, context);
 		Assert.assertNotNull(invoice);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index f09a520..1be0585 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -33,7 +33,7 @@ import com.ning.billing.entitlement.api.billing.DefaultBillingEvent;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.model.BillingEventSet;
@@ -79,14 +79,14 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         }
 
         @Override
-        public boolean isEventProcessingOff() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
         public int getNumberOfMonthsInFuture() {
             return 36;
         }
+
+		@Override
+		public boolean isNotificationProcessingOff() {
+            throw new UnsupportedOperationException();			
+		}
     };
 
     private final InvoiceGenerator generator;

jaxrs/pom.xml 97(+97 -0)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
new file mode 100644
index 0000000..f8472a9
--- /dev/null
+++ b/jaxrs/pom.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 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</artifactId>
+        <version>0.1.11-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-jaxrs</artifactId>
+    <name>killbill-jaxrs</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>jsr311-api</artifactId>
+            <!-- WHY DO WE NEED VESRION HERE ?? -->
+            <version>1.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.skife.config</groupId>
+            <artifactId>config-magic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-jaxrs</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
new file mode 100644
index 0000000..13ad140
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTimeZone;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.catalog.api.Currency;
+
+public class AccountJson {
+
+    // Missing city, locale, postalCode from https://home.ninginc.com:8443/display/REVINFRA/Killbill+1.0+APIs
+
+    private final String acountId;
+    private final String name;
+    private final Integer length;
+    private final String externalKey;
+    private final String email;
+    private final Integer billCycleDay;
+    private final String currency;
+    private final String paymentProvider;
+    private final String timeZone;
+    private final String address1;
+    private final String address2;
+    private final String company;
+    private final String state;
+    private final String country;
+    private final String phone;
+
+
+    public AccountJson(Account account) {
+        this.acountId = account.getId().toString();
+        this.name = account.getName();
+        this.length = account.getFirstNameLength();
+        this.externalKey = account.getExternalKey();
+        this.email = account.getEmail();
+        this.billCycleDay = account.getBillCycleDay();
+        this.currency = account.getCurrency().toString();
+        this.paymentProvider = account.getPaymentProviderName();
+        this.timeZone = account.getTimeZone().toString();
+        this.address1 = account.getAddress1();
+        this.address2 = account.getAddress2();
+        this.company = account.getCompanyName();
+        this.state = account.getStateOrProvince();
+        this.country = account.getCountry();
+        this.phone = account.getPhone();
+    }
+    
+    public AccountData toAccountData() {
+        return new AccountData() {
+            @Override
+            public DateTimeZone getTimeZone() {
+                return (timeZone != null) ? DateTimeZone.forID(timeZone) : null;
+            }
+            @Override
+            public String getStateOrProvince() {
+                return state;
+            }
+            @Override
+            public String getPostalCode() {
+                return null;
+            }
+            @Override
+            public String getPhone() {
+                return phone;
+            }
+            @Override
+            public String getPaymentProviderName() {
+                return paymentProvider;
+            }
+            @Override
+            public String getName() {
+                return name;
+            }
+            @Override
+            public String getLocale() {
+                return null;
+            }
+            @Override
+            public int getFirstNameLength() {
+                return length;
+            }
+            @Override
+            public String getExternalKey() {
+                return externalKey;
+            }
+            @Override
+            public String getEmail() {
+                return email;
+            }
+            @Override
+            public Currency getCurrency() {
+                Currency result =  (currency != null) ? Currency.valueOf(currency) : Currency.USD;
+                return result;
+            }
+            @Override
+            public String getCountry() {
+                return country;
+            }
+            @Override
+            public String getCompanyName() {
+                return company;
+            }
+            @Override
+            public String getCity() {
+                return null;
+            }
+            @Override
+            public int getBillCycleDay() {
+                return billCycleDay;
+            }
+            @Override
+            public String getAddress2() {
+                return address2;
+            }
+            @Override
+            public String getAddress1() {
+                return address1;
+            }
+        };
+    }
+
+    // Seems like Jackson (JacksonJsonProvider.readFrom(Class<Object>, Type, Annotation[], MediaType, MultivaluedMap<String,String>, InputStream) line: 443)
+    // needs us to define a default CTOR to instanciate the class first.
+    public AccountJson() {
+        this.acountId = null;
+        this.name = null;
+        this.length = null;
+        this.externalKey = null;
+        this.email = null;
+        this.billCycleDay = null;
+        this.currency = null;
+        this.paymentProvider = null;
+        this.timeZone = null;
+        this.address1 = null;
+        this.address2 = null;
+        this.company = null;
+        this.state = null;
+        this.country = null;
+        this.phone = null;
+    }
+
+    @JsonCreator
+    public AccountJson(@JsonProperty("account_id") String acountId,
+            @JsonProperty("name") String name,
+            @JsonProperty("first_name_length") Integer length,
+            @JsonProperty("external_key") String externalKey,
+            @JsonProperty("email") String email,
+            @JsonProperty("billing_day") Integer billCycleDay,
+            @JsonProperty("currency") String currency,
+            @JsonProperty("payment_provider") String paymentProvider,
+            @JsonProperty("timezone") String timeZone,
+            @JsonProperty("address1") String address1,
+            @JsonProperty("address2") String address2,
+            @JsonProperty("company") String company,
+            @JsonProperty("state") String state,
+            @JsonProperty("country") String country,
+            @JsonProperty("phone") String phone) {
+        super();
+        this.acountId = acountId;
+        this.name = name;
+        this.length = length;
+        this.externalKey = externalKey;
+        this.email = email;
+        this.billCycleDay = billCycleDay;
+        this.currency = currency;
+        this.paymentProvider = paymentProvider;
+        this.timeZone = timeZone;
+        this.address1 = address1;
+        this.address2 = address2;
+        this.company = company;
+        this.state = state;
+        this.country = country;
+        this.phone = phone;
+    }
+
+    public String getAcountId() {
+        return acountId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Integer getLength() {
+        return length;
+    }
+
+    public String getExternalKey() {
+        return externalKey;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public Integer getBillCycleDay() {
+        return billCycleDay;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public String getPaymentProvider() {
+        return paymentProvider;
+    }
+
+    public String getTimeZone() {
+        return timeZone;
+    }
+
+    public String getAddress1() {
+        return address1;
+    }
+
+    public String getAddress2() {
+        return address2;
+    }
+
+    public String getCompany() {
+        return company;
+    }
+
+    public String getState() {
+        return state;
+    }
+
+    public String getCountry() {
+        return country;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((acountId == null) ? 0 : acountId.hashCode());
+		result = prime * result
+				+ ((address1 == null) ? 0 : address1.hashCode());
+		result = prime * result
+				+ ((address2 == null) ? 0 : address2.hashCode());
+		result = prime * result
+				+ ((billCycleDay == null) ? 0 : billCycleDay.hashCode());
+		result = prime * result + ((company == null) ? 0 : company.hashCode());
+		result = prime * result + ((country == null) ? 0 : country.hashCode());
+		result = prime * result
+				+ ((currency == null) ? 0 : currency.hashCode());
+		result = prime * result + ((email == null) ? 0 : email.hashCode());
+		result = prime * result
+				+ ((externalKey == null) ? 0 : externalKey.hashCode());
+		result = prime * result + ((length == null) ? 0 : length.hashCode());
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		result = prime * result
+				+ ((paymentProvider == null) ? 0 : paymentProvider.hashCode());
+		result = prime * result + ((phone == null) ? 0 : phone.hashCode());
+		result = prime * result + ((state == null) ? 0 : state.hashCode());
+		result = prime * result
+				+ ((timeZone == null) ? 0 : timeZone.hashCode());
+		return result;
+	}
+
+	// Used to check POST versus GET
+	public boolean equalsNoId(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		AccountJson other = (AccountJson) obj;
+		if (address1 == null) {
+			if (other.address1 != null)
+				return false;
+		} else if (!address1.equals(other.address1))
+			return false;
+		if (address2 == null) {
+			if (other.address2 != null)
+				return false;
+		} else if (!address2.equals(other.address2))
+			return false;
+		if (billCycleDay == null) {
+			if (other.billCycleDay != null)
+				return false;
+		} else if (!billCycleDay.equals(other.billCycleDay))
+			return false;
+		if (company == null) {
+			if (other.company != null)
+				return false;
+		} else if (!company.equals(other.company))
+			return false;
+		if (country == null) {
+			if (other.country != null)
+				return false;
+		} else if (!country.equals(other.country))
+			return false;
+		if (currency == null) {
+			if (other.currency != null)
+				return false;
+		} else if (!currency.equals(other.currency))
+			return false;
+		if (email == null) {
+			if (other.email != null)
+				return false;
+		} else if (!email.equals(other.email))
+			return false;
+		if (externalKey == null) {
+			if (other.externalKey != null)
+				return false;
+		} else if (!externalKey.equals(other.externalKey))
+			return false;
+		if (length == null) {
+			if (other.length != null)
+				return false;
+		} else if (!length.equals(other.length))
+			return false;
+		if (name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!name.equals(other.name))
+			return false;
+		if (paymentProvider == null) {
+			if (other.paymentProvider != null)
+				return false;
+		} else if (!paymentProvider.equals(other.paymentProvider))
+			return false;
+		if (phone == null) {
+			if (other.phone != null)
+				return false;
+		} else if (!phone.equals(other.phone))
+			return false;
+		if (state == null) {
+			if (other.state != null)
+				return false;
+		} else if (!state.equals(other.state))
+			return false;
+		if (timeZone == null) {
+			if (other.timeZone != null)
+				return false;
+		} else if (!timeZone.equals(other.timeZone))
+			return false;
+		return true;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (equalsNoId(obj) == false) {
+			return false;
+		} else {
+			AccountJson other = (AccountJson) obj;
+			if (acountId == null) {
+				if (other.acountId != null)
+					return false;
+			} else if (!acountId.equals(other.acountId))
+				return false;
+		}
+		return true;
+	}
+ }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJson.java
new file mode 100644
index 0000000..12543cc
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJson.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonView;
+
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
+public class BundleJson {
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String bundleId;
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String accountId;
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String externalKey;
+
+    @JsonView(BundleTimelineViews.Timeline.class)
+    private final List<SubscriptionJson> subscriptions;
+
+    @JsonCreator
+    public BundleJson(@JsonProperty("bundle_id") String bundleId,
+            @JsonProperty("account_id") String accountId,
+            @JsonProperty("external_key") String externalKey,
+            @JsonProperty("subscriptions") List<SubscriptionJson> subscriptions) {
+        super();
+        this.bundleId = bundleId;
+        this.accountId = accountId;
+        this.externalKey = externalKey;
+        this.subscriptions = subscriptions;
+    }
+
+    public String getBundleId() {
+        return bundleId;
+    }
+
+    public String getAccountId() {
+        return accountId;
+    }
+
+    public String getExternalKey() {
+        return externalKey;
+    }
+
+    public List<SubscriptionJson> getSubscriptions() {
+        return subscriptions;
+    }
+    
+    public BundleJson(SubscriptionBundle bundle) {
+        this.bundleId = bundle.getId().toString();
+        this.accountId = bundle.getAccountId().toString();
+        this.externalKey = bundle.getKey();
+        this.subscriptions = null;
+    }
+    
+    public BundleJson() {
+        this.bundleId = null;
+        this.accountId = null;
+        this.externalKey = null;
+        this.subscriptions = null;
+    }
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((accountId == null) ? 0 : accountId.hashCode());
+		result = prime * result
+				+ ((bundleId == null) ? 0 : bundleId.hashCode());
+		result = prime * result
+				+ ((externalKey == null) ? 0 : externalKey.hashCode());
+		result = prime * result
+				+ ((subscriptions == null) ? 0 : subscriptions.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (equalsNoId(obj) == false) {
+			return false;
+		}
+		BundleJson other = (BundleJson) obj;
+		if (bundleId == null) {
+			if (other.bundleId != null)
+				return false;
+		} else if (!bundleId.equals(other.bundleId))
+			return false;
+		return true;
+	}
+
+	public boolean equalsNoId(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		BundleJson other = (BundleJson) obj;
+		if (accountId == null) {
+			if (other.accountId != null)
+				return false;
+		} else if (!accountId.equals(other.accountId))
+			return false;
+		if (externalKey == null) {
+			if (other.externalKey != null)
+				return false;
+		} else if (!externalKey.equals(other.externalKey))
+			return false;
+		if (subscriptions == null) {
+			if (other.subscriptions != null)
+				return false;
+		} else if (!subscriptions.equals(other.subscriptions))
+			return false;
+		return true;
+	}
+    
+    
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java
new file mode 100644
index 0000000..61761a7
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonView;
+
+public class BundleTimelineJson {
+
+    @JsonView(BundleTimelineViews.Timeline.class)
+    private final String viewId;
+
+    @JsonView(BundleTimelineViews.Timeline.class)
+    private final BundleJson bundle;
+
+    @JsonView(BundleTimelineViews.ReadTimeline.class)
+    private final List<PaymentJson> payments;
+
+    @JsonView(BundleTimelineViews.ReadTimeline.class)
+    private final List<InvoiceJson> invoices;
+
+    @JsonView(BundleTimelineViews.WriteTimeline.class)
+    private final String resonForChange;
+
+    @JsonCreator
+    public BundleTimelineJson(@JsonProperty("view_id") String viewId,
+            @JsonProperty("bundle") BundleJson bundle,
+            @JsonProperty("payments") List<PaymentJson> payments,
+            @JsonProperty("invoices") List<InvoiceJson> invoices,
+            @JsonProperty("reason_for_change") String reason) {
+        this.viewId = viewId;
+        this.bundle = bundle;
+        this.payments = payments;
+        this.invoices = invoices;
+        this.resonForChange = reason;
+    }
+
+    public String getViewId() {
+        return viewId;
+    }
+
+    public BundleJson getBundle() {
+        return bundle;
+    }
+
+    public List<PaymentJson> getPayments() {
+        return payments;
+    }
+
+    public List<InvoiceJson> getInvoices() {
+        return invoices;
+    }
+
+    public String getResonForChange() {
+        return resonForChange;
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineViews.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineViews.java
new file mode 100644
index 0000000..020764e
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineViews.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+
+public class BundleTimelineViews {
+    static class Base {};
+    static class Timeline extends Base {};
+    static class ReadTimeline extends Timeline {};
+    static class WriteTimeline extends Timeline {};
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java
new file mode 100644
index 0000000..b13bdee
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.math.BigDecimal;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+public class InvoiceJson {
+
+    private final BigDecimal amount;
+    private final String invoiceId;
+    private final DateTime requestedDate;
+    private final String invoiceNumber;
+    private final BigDecimal balance;
+
+    @JsonCreator
+    public InvoiceJson(@JsonProperty("amount") BigDecimal amount,
+            @JsonProperty("invoice_id") String invoiceId,
+            @JsonProperty("requested_dt") DateTime requestedDate,
+            @JsonProperty("invoice_number") String invoiceNumber,
+            @JsonProperty("balance") BigDecimal balance) {
+        super();
+        this.amount = amount;
+        this.invoiceId = invoiceId;
+        this.requestedDate = requestedDate;
+        this.invoiceNumber = invoiceNumber;
+        this.balance = balance;
+    }
+
+    public BigDecimal getAmount() {
+        return amount;
+    }
+
+    public String getInvoiceId() {
+        return invoiceId;
+    }
+
+    public DateTime getRequestedDate() {
+        return requestedDate;
+    }
+
+    public String getInvoiceNumber() {
+        return invoiceNumber;
+    }
+
+    public BigDecimal getBalance() {
+        return balance;
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java
new file mode 100644
index 0000000..1f932d4
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.math.BigDecimal;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.clock.DefaultClock;
+
+public class PaymentJson {
+
+    private final BigDecimal paidAmount;
+    private final String invoiceId;
+    private final String paymentId;
+    private final DateTime requestedDate;
+    private final DateTime effectiveDate;
+    private final String status;
+
+    @JsonCreator
+    public PaymentJson(@JsonProperty("paid_amount") BigDecimal paidAmount,
+            @JsonProperty("invoice_id") String invoiceId,
+            @JsonProperty("payment_id") String paymentId,
+            @JsonProperty("requested_dt") DateTime requestedDate,
+            @JsonProperty("effective_dt") DateTime effectiveDate,
+            @JsonProperty("status") String status) {
+        super();
+        this.paidAmount = paidAmount;
+        this.invoiceId = invoiceId;
+        this.paymentId = paymentId;
+        this.requestedDate = DefaultClock.toUTCDateTime(requestedDate);
+        this.effectiveDate = DefaultClock.toUTCDateTime(effectiveDate);
+        this.status = status;
+    }
+
+    public BigDecimal getPaidAmount() {
+        return paidAmount;
+    }
+
+    public String getInvoiceId() {
+        return invoiceId;
+    }
+
+    public String getPaymentId() {
+        return paymentId;
+    }
+
+    public DateTime getRequestedDate() {
+        return DefaultClock.toUTCDateTime(requestedDate);
+    }
+
+    public DateTime getEffectiveDate() {
+        return DefaultClock.toUTCDateTime(effectiveDate);
+    }
+
+    public String getStatus() {
+        return status;
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java
new file mode 100644
index 0000000..0619020
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonView;
+import org.joda.time.DateTime;
+
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.util.clock.DefaultClock;
+
+public class SubscriptionJson {
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String subscriptionId;
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String bundleId;
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String productName;
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String productCategory;
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String billingPeriod;
+
+    @JsonView(BundleTimelineViews.Base.class)
+    private final String priceList;
+
+    @JsonView(BundleTimelineViews.ReadTimeline.class)
+    private final List<SubscriptionReadEventJson> events;
+
+    @JsonView(BundleTimelineViews.WriteTimeline.class)
+    private final List<SubscriptionDeletedEventJson> deletedEvents;
+
+    @JsonView(BundleTimelineViews.WriteTimeline.class)
+    private final List<SubscriptionNewEventJson> newEvents;
+
+
+    public static class SubscriptionReadEventJson extends SubscriptionBaseEventJson {
+
+        @JsonView(BundleTimelineViews.Timeline.class)
+        private final String eventId;
+
+        @JsonView(BundleTimelineViews.Timeline.class)
+        private final DateTime effectiveDate;
+
+        @JsonCreator
+        public SubscriptionReadEventJson(@JsonProperty("event_id") String eventId,
+                @JsonProperty("billing_period") String billingPeriod,
+                @JsonProperty("requested_dt") DateTime requestedDate,
+                @JsonProperty("effective_dt") DateTime effectiveDate,
+                @JsonProperty("product") String product,
+                @JsonProperty("price_list") String priceList,
+                @JsonProperty("event_type") String eventType,
+                @JsonProperty("phase") String phase) {
+            super(billingPeriod, requestedDate, product, priceList, eventType, phase);
+            this.eventId = eventId;
+            this.effectiveDate = effectiveDate;
+        }
+
+        public String getEventId() {
+            return eventId;
+        }
+
+        public DateTime getEffectiveDate() {
+            return DefaultClock.toUTCDateTime(effectiveDate);
+        }
+
+        @Override
+        public String toString() {
+            return "SubscriptionReadEventJson [eventId=" + eventId
+                    + ", effectiveDate=" + effectiveDate
+                    + ", getBillingPeriod()=" + getBillingPeriod()
+                    + ", getRequestedDate()=" + getRequestedDate()
+                    + ", getProduct()=" + getProduct() + ", getPriceList()="
+                    + getPriceList() + ", getEventType()=" + getEventType()
+                    + ", getPhase()=" + getPhase() + ", getClass()="
+                    + getClass() + ", hashCode()=" + hashCode()
+                    + ", toString()=" + super.toString() + "]";
+        }
+    }
+
+    public static class SubscriptionDeletedEventJson extends SubscriptionReadEventJson {
+        @JsonCreator
+        public SubscriptionDeletedEventJson(@JsonProperty("event_id") String eventId,
+                @JsonProperty("billing_period") String billingPeriod,
+                @JsonProperty("requested_dt") DateTime requestedDate,
+                @JsonProperty("effective_dt") DateTime effectiveDate,
+                @JsonProperty("product") String product,
+                @JsonProperty("price_list") String priceList,
+                @JsonProperty("event_type") String eventType,
+                @JsonProperty("phase") String phase) {
+            super(eventId, billingPeriod, requestedDate, effectiveDate, product, priceList, eventType, phase);
+
+        }
+    }
+
+
+    public static class SubscriptionNewEventJson extends SubscriptionBaseEventJson {
+        @JsonCreator
+        public SubscriptionNewEventJson(@JsonProperty("billing_period") String billingPeriod,
+                @JsonProperty("requested_dt") DateTime requestedDate,
+                @JsonProperty("product") String product,
+                @JsonProperty("price_list") String priceList,
+                @JsonProperty("event_type") String eventType,
+                @JsonProperty("phase") String phase) {
+            super(billingPeriod, requestedDate, product, priceList, eventType, phase);
+        }
+
+        @Override
+        public String toString() {
+            return "SubscriptionNewEventJson [getBillingPeriod()="
+                    + getBillingPeriod() + ", getRequestedDate()="
+                    + getRequestedDate() + ", getProduct()=" + getProduct()
+                    + ", getPriceList()=" + getPriceList()
+                    + ", getEventType()=" + getEventType() + ", getPhase()="
+                    + getPhase() + ", getClass()=" + getClass()
+                    + ", hashCode()=" + hashCode() + ", toString()="
+                    + super.toString() + "]";
+        }
+    }
+
+    public static class SubscriptionBaseEventJson {
+
+        @JsonView(BundleTimelineViews.Timeline.class)
+        private final String billingPeriod;
+
+        @JsonView(BundleTimelineViews.Timeline.class)
+        private final DateTime requestedDate;
+
+
+        @JsonView(BundleTimelineViews.Timeline.class)
+        private final String product;
+
+        @JsonView(BundleTimelineViews.Timeline.class)
+        private final String priceList;
+
+        @JsonView(BundleTimelineViews.Timeline.class)
+        private final String eventType;
+
+        @JsonView(BundleTimelineViews.Timeline.class)
+        private final String phase;
+
+        @JsonCreator
+        public SubscriptionBaseEventJson(@JsonProperty("billing_period") String billingPeriod,
+                @JsonProperty("requested_dt") DateTime requestedDate,
+                @JsonProperty("product") String product,
+                @JsonProperty("price_list") String priceList,
+                @JsonProperty("event_type") String eventType,
+                @JsonProperty("phase") String phase) {
+            super();
+            this.billingPeriod = billingPeriod;
+            this.requestedDate = DefaultClock.toUTCDateTime(requestedDate);
+            this.product = product;
+            this.priceList = priceList;
+            this.eventType = eventType;
+            this.phase = phase;
+        }
+
+        public String getBillingPeriod() {
+            return billingPeriod;
+        }
+
+        public DateTime getRequestedDate() {
+            return DefaultClock.toUTCDateTime(requestedDate);
+        }
+
+        public String getProduct() {
+            return product;
+        }
+
+        public String getPriceList() {
+            return priceList;
+        }
+
+        public String getEventType() {
+            return eventType;
+        }
+
+        public String getPhase() {
+            return phase;
+        }
+    }
+
+
+    @JsonCreator
+    public SubscriptionJson(@JsonProperty("subscription_id") String subscriptionId,
+            @JsonProperty("bundle_id") String bundleId,
+            @JsonProperty("product_name") String productName,
+            @JsonProperty("product_category") String productCategory,
+            @JsonProperty("billing_period") String billingPeriod,
+            @JsonProperty("price_list") String priceList,
+            @JsonProperty("events") List<SubscriptionReadEventJson> events,
+            @JsonProperty("new_events") List<SubscriptionNewEventJson> newEvents,
+            @JsonProperty("deleted_events") List<SubscriptionDeletedEventJson> deletedEvents) {
+        super();
+        this.subscriptionId = subscriptionId;
+        this.bundleId = bundleId;
+        this.productName = productName;
+        this.productCategory = productCategory;
+        this.billingPeriod = billingPeriod;
+        this.priceList = priceList;
+        this.events = events;
+        this.deletedEvents = deletedEvents;
+        this.newEvents = newEvents;
+    }
+    
+    public SubscriptionJson() {
+        this.subscriptionId = null;
+        this.bundleId = null;
+        this.productName = null;
+        this.productCategory = null;
+        this.billingPeriod = null;
+        this.priceList = null;
+        this.events = null;
+        this.deletedEvents = null;
+        this.newEvents = null;
+    }
+    
+    public SubscriptionJson(final Subscription data,
+    		List<SubscriptionReadEventJson> events, List<SubscriptionDeletedEventJson> deletedEvents, List<SubscriptionNewEventJson> newEvents) {
+        this.subscriptionId = data.getId().toString();
+        this.bundleId = data.getBundleId().toString();
+        this.productName = data.getCurrentPlan().getProduct().getName();
+        this.productCategory = data.getCurrentPlan().getProduct().getCategory().toString();
+        this.billingPeriod = data.getCurrentPlan().getBillingPeriod().toString();
+        this.priceList = data.getCurrentPriceList().getName();
+        this.events = events;
+        this.deletedEvents = deletedEvents;
+        this.newEvents = newEvents;
+    }
+
+    public String getSubscriptionId() {
+        return subscriptionId;
+    }
+
+    public String getBundleId() {
+        return bundleId;
+    }
+
+    public String getProductName() {
+        return productName;
+    }
+
+    public String getProductCategory() {
+        return productCategory;
+    }
+
+    public String getBillingPeriod() {
+        return billingPeriod;
+    }
+
+    public String getPriceList() {
+        return priceList;
+    }
+
+    public List<SubscriptionReadEventJson> getEvents() {
+        return events;
+    }
+
+    public List<SubscriptionNewEventJson> getNewEvents() {
+        return newEvents;
+    }
+
+    public List<SubscriptionDeletedEventJson> getDeletedEvents() {
+        return deletedEvents;
+    }
+
+    @Override
+    public String toString() {
+        return "SubscriptionJson [subscriptionId=" + subscriptionId
+                + ", bundleId=" + bundleId + ", productName=" + productName
+                + ", productCategory=" + productCategory + ", billingPeriod="
+                + billingPeriod + ", priceList=" + priceList + ", events="
+                + events + ", deletedEvents=" + deletedEvents + ", newEvents="
+                + newEvents + "]";
+    }
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((billingPeriod == null) ? 0 : billingPeriod.hashCode());
+		result = prime * result
+				+ ((bundleId == null) ? 0 : bundleId.hashCode());
+		result = prime * result
+				+ ((priceList == null) ? 0 : priceList.hashCode());
+		result = prime * result
+				+ ((productCategory == null) ? 0 : productCategory.hashCode());
+		result = prime * result
+				+ ((productName == null) ? 0 : productName.hashCode());
+		result = prime * result
+				+ ((subscriptionId == null) ? 0 : subscriptionId.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (equalsNoId(obj) == false) {
+			return false;
+		}
+		SubscriptionJson other = (SubscriptionJson) obj;
+		if (subscriptionId == null) {
+			if (other.subscriptionId != null)
+				return false;
+		} else if (!subscriptionId.equals(other.subscriptionId))
+			return false;
+		return true;
+	}
+
+	public boolean equalsNoId(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		SubscriptionJson other = (SubscriptionJson) obj;
+		if (billingPeriod == null) {
+			if (other.billingPeriod != null)
+				return false;
+		} else if (!billingPeriod.equals(other.billingPeriod))
+			return false;
+		if (bundleId == null) {
+			if (other.bundleId != null)
+				return false;
+		} else if (!bundleId.equals(other.bundleId))
+			return false;
+		if (priceList == null) {
+			if (other.priceList != null)
+				return false;
+		} else if (!priceList.equals(other.priceList))
+			return false;
+		if (productCategory == null) {
+			if (other.productCategory != null)
+				return false;
+		} else if (!productCategory.equals(other.productCategory))
+			return false;
+		if (productName == null) {
+			if (other.productName != null)
+				return false;
+		} else if (!productName.equals(other.productName))
+			return false;
+		return true;
+	}
+    
+    
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
new file mode 100644
index 0000000..49203f5
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.Response.Status;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.json.BundleJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+
+
+@Singleton
+@Path(BaseJaxrsResource.ACCOUNTS_PATH)
+public class AccountResource implements BaseJaxrsResource {
+
+    private static final Logger log = LoggerFactory.getLogger(AccountResource.class);
+
+    private final AccountUserApi accountApi;
+    private final EntitlementUserApi entitlementApi;
+    private final Context context;
+    private final JaxrsUriBuilder uriBuilder;
+
+    @Inject
+    public AccountResource(final JaxrsUriBuilder uriBuilder, final AccountUserApi accountApi, final EntitlementUserApi entitlementApi, final Context context) {
+        this.uriBuilder = uriBuilder;
+    	this.accountApi = accountApi;
+        this.entitlementApi = entitlementApi;
+        this.context = context;
+    }
+
+    @GET
+    @Path("/{accountId:" + UUID_PATTERN + "}")
+    @Produces(APPLICATION_JSON)
+    public Response getAccount(@PathParam("accountId") String accountId) {
+        Account account = accountApi.getAccountById(UUID.fromString(accountId));
+        if (account == null) {
+        	return Response.status(Status.NO_CONTENT).build();
+        }
+        AccountJson json = new AccountJson(account);
+        return Response.status(Status.OK).entity(json).build();
+    }
+
+    @GET
+    @Path("/{accountId:" + UUID_PATTERN + "}/" + BUNDLES)
+    @Produces(APPLICATION_JSON)
+    public Response getAccountBundles(@PathParam("accountId") String accountId) {
+
+    	UUID uuid = UUID.fromString(accountId);
+    	Account account = accountApi.getAccountById(uuid);
+    	if (account == null) {
+    		return Response.status(Status.NO_CONTENT).build();    		
+    	}
+    	List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(uuid);
+    	Collection<BundleJson> result = Collections2.transform(bundles, new Function<SubscriptionBundle, BundleJson>() {
+			@Override
+			public BundleJson apply(SubscriptionBundle input) {
+				return new BundleJson(input);
+			}
+		});
+        return Response.status(Status.OK).entity(result).build();
+    }
+
+    
+    @GET
+    @Produces(APPLICATION_JSON)
+    public Response getAccountByKey(@QueryParam(QUERY_EXTERNAL_KEY) String externalKey) {
+        Account account = null;
+        if (externalKey != null) {
+            account = accountApi.getAccountByKey(externalKey);
+        }
+        if (account == null) {
+            return Response.status(Status.NO_CONTENT).build();
+        }
+        AccountJson json = new AccountJson(account);
+        return Response.status(Status.OK).entity(json).build();
+    }
+
+    
+    @POST
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    public Response createAccount(AccountJson json) {
+
+        try {
+        	
+            AccountData data = json.toAccountData();
+            final Account account = accountApi.createAccount(data, null, null, context.createContext());
+            URI uri = UriBuilder.fromPath(account.getId().toString()).build();
+            return uriBuilder.buildResponse(AccountResource.class, "getAccount", account.getId());
+        } catch (AccountApiException e) {
+            log.info(String.format("Failed to create account %s", json), e);
+            return Response.status(Status.BAD_REQUEST).build();
+        }
+    }
+
+    @PUT
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    @Path("/{accountId:" + UUID_PATTERN + "}")
+    public Response updateAccount(AccountJson json, @PathParam("accountId") String accountId) {
+        try {
+            AccountData data = json.toAccountData();
+            UUID uuid = UUID.fromString(accountId);
+            accountApi.updateAccount(uuid, data, context.createContext());
+            return getAccount(accountId);
+        } catch (AccountApiException e) {
+        	if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+        		return Response.status(Status.NO_CONTENT).build();        		
+        	} else {
+        		log.info(String.format("Failed to update account %s with %s", accountId, json), e);
+        		return Response.status(Status.BAD_REQUEST).build();
+        	}
+        }
+    }
+
+    // Not supported
+    @DELETE
+    @Path("/{accountId:" + UUID_PATTERN + "}")
+    @Produces(APPLICATION_JSON)
+    public Response cancelAccount(@PathParam("accountId") String accountId) {
+        /*
+        try {
+            accountApi.cancelAccount(accountId);
+            return Response.status(Status.NO_CONTENT).build();
+        } catch (AccountApiException e) {
+            log.info(String.format("Failed to cancel account %s", accountId), e);
+            return Response.status(Status.BAD_REQUEST).build();
+        }
+       */
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BaseJaxrsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BaseJaxrsResource.java
new file mode 100644
index 0000000..3fb0334
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BaseJaxrsResource.java
@@ -0,0 +1,45 @@
+/* 
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+public interface BaseJaxrsResource {
+	
+	public static final String API_PREFIX = "";
+	public static final String API_VERSION = "/1.0";
+	
+	/*
+	 * Patterns
+	 */
+	public static String UUID_PATTERN = "\\w+-\\w+-\\w+-\\w+-\\w+";
+	
+	/*
+	 * Query parameters
+	 */
+	public static final String QUERY_EXTERNAL_KEY = "external_key";
+	public static final String QUERY_REQUESTED_DT = "requested_date";
+	public static final String QUERY_CALL_COMPLETION = "call_completion";
+	public static final String QUERY_CALL_TIMEOUT = "call_timeout_sec";	
+	
+	public static final String ACCOUNTS = "accounts";	
+	public static final String ACCOUNTS_PATH = API_PREFIX + API_VERSION + "/" + ACCOUNTS;
+	
+	public static final String BUNDLES = "bundles";		
+	public static final String BUNDLES_PATH = API_PREFIX + API_VERSION + "/" + BUNDLES;
+
+	public static final String SUBSCRIPTIONS = "subscriptions";		
+	public static final String SUBSCRIPTIONS_PATH = API_PREFIX + API_VERSION + "/" + SUBSCRIPTIONS;
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
new file mode 100644
index 0000000..d6a94ab
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.inject.Inject;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.jaxrs.json.BundleJson;
+import com.ning.billing.jaxrs.json.SubscriptionJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+
+@Path(BaseJaxrsResource.BUNDLES_PATH)
+public class BundleResource implements BaseJaxrsResource {
+
+	private static final Logger log = LoggerFactory.getLogger(BundleResource.class);
+
+	private final EntitlementUserApi entitlementApi;
+	private final Context context;
+    private final JaxrsUriBuilder uriBuilder;	
+
+    @Inject
+	public BundleResource(final JaxrsUriBuilder uriBuilder, final EntitlementUserApi entitlementApi, final Context context) {
+	    this.uriBuilder = uriBuilder;
+		this.entitlementApi = entitlementApi;
+		this.context = context;
+	}
+
+	@GET
+	@Path("/{bundleId:"  + UUID_PATTERN + "}")
+	@Produces(APPLICATION_JSON)
+	public Response getBundle(@PathParam("bundleId") final String bundleId) {
+		SubscriptionBundle bundle = entitlementApi.getBundleFromId(UUID.fromString(bundleId));
+		if (bundle == null) {
+			return Response.status(Status.NO_CONTENT).build();
+		}
+		BundleJson json = new BundleJson(bundle);
+		return Response.status(Status.OK).entity(json).build();
+	}
+
+	@GET
+	@Produces(APPLICATION_JSON)
+	public Response getBundleByKey(@QueryParam(QUERY_EXTERNAL_KEY) final String externalKey) {
+		SubscriptionBundle bundle = entitlementApi.getBundleForKey(externalKey);
+		if (bundle == null) {
+			return Response.status(Status.NO_CONTENT).build();
+		}
+		BundleJson json = new BundleJson(bundle);
+		return Response.status(Status.OK).entity(json).build();
+	}
+
+	@POST
+	@Consumes(APPLICATION_JSON)
+	@Produces(APPLICATION_JSON)
+	public Response createBundle(final BundleJson json) {
+		try {
+			UUID accountId = UUID.fromString(json.getAccountId());
+			final SubscriptionBundle bundle = entitlementApi.createBundleForAccount(accountId, json.getExternalKey(), context.createContext());
+            return uriBuilder.buildResponse(BundleResource.class, "getBundle", bundle.getId());
+		} catch (EntitlementUserApiException e) {
+			log.info(String.format("Failed to create bundle %s", json), e);
+			return Response.status(Status.BAD_REQUEST).build();
+		}
+	}
+	
+	@GET
+	@Path("/{bundleId:" + UUID_PATTERN + "}/" + SUBSCRIPTIONS)
+	@Produces(APPLICATION_JSON)
+	public Response getBundleSubscriptions(@PathParam("bundleId") final String bundleId) {
+		
+		UUID uuid = UUID.fromString(bundleId);
+		SubscriptionBundle bundle = entitlementApi.getBundleFromId(uuid);
+		if (bundle == null) {
+			return Response.status(Status.NO_CONTENT).build();
+		}
+		List<Subscription> bundles = entitlementApi.getSubscriptionsForBundle(uuid);
+		Collection<SubscriptionJson> result =  Collections2.transform(bundles, new Function<Subscription, SubscriptionJson>() {
+			@Override
+			public SubscriptionJson apply(Subscription input) {
+				return new SubscriptionJson(input, null, null, null);
+			}
+		});
+		return Response.status(Status.OK).entity(result).build();
+	}
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleTimelineResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleTimelineResource.java
new file mode 100644
index 0000000..6386a5b
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleTimelineResource.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+
+@Path("/1.0/timeline/bundle")
+public class BundleTimelineResource {
+
+    @GET
+    @Path("/{bundleId:\\\\w+-\\\\w+-\\\\w+-\\\\w+-\\\\w+}")
+    @Produces(APPLICATION_JSON)
+    public Response getBundleTimeline(@PathParam("bundleId") String bundleId) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+
+    @POST
+    @Produces(APPLICATION_JSON)
+    @Consumes(APPLICATION_JSON)
+    @Path("/{bundleId:\\w+-\\w+-\\w+-\\w+-\\w+}/repair")
+     public Response repairBundleTineline(BundleTimelineResource bundle,
+             @PathParam("bundleId") String bundleId) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
new file mode 100644
index 0000000..e5a1c97
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import com.ning.billing.jaxrs.json.InvoiceJson;
+
+
+
+@Path("/1.0/invoice")
+public class InvoiceResource {
+
+
+    @GET
+    @Produces(APPLICATION_JSON)
+    public Response getInvoices(@QueryParam("accountId") String accountId) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+
+    @GET
+    @Path("/{invoiceId:\\w+-\\w+-\\w+-\\w+-\\w+}")
+    @Produces(APPLICATION_JSON)
+    public Response getInvoice(@PathParam("invoiceId") String accountId) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+
+    @POST
+    @Path("/{accountId:\\w+-\\w+-\\w+-\\w+-\\w+}")
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    public Response createFutureInvoice(InvoiceJson invoice,
+            @PathParam("accountId") String accountId,
+            @QueryParam("targetDate") String targetDate) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
new file mode 100644
index 0000000..c2f5391
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import com.ning.billing.jaxrs.json.PaymentJson;
+
+
+@Path("/1.0/payment")
+public class PaymentResource {
+
+
+    @GET
+    @Path("/{invoiceId:\\w+-\\w+-\\w+-\\w+-\\w+}")
+    @Produces(APPLICATION_JSON)
+    public Response getPayments(@PathParam("invoiceId") String invoiceId) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+
+    @GET
+    @Path("/account/{accountId:\\w+-\\w+-\\w+-\\w+-\\w+}")
+    @Produces(APPLICATION_JSON)
+    public Response getAllPayments(@PathParam("accountId") String accountId) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+
+    @POST
+    @Produces(APPLICATION_JSON)
+    @Consumes(APPLICATION_JSON)
+    @Path("/{invoiceId:\\w+-\\w+-\\w+-\\w+-\\w+}")
+    public Response createInstantPayment(PaymentJson payment,
+            @PathParam("invoiceId") String invoiceId,
+            @QueryParam("last4CC") String last4CC,
+            @QueryParam("nameOnCC") String nameOnCC) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
new file mode 100644
index 0000000..8c5c5bd
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+import java.util.concurrent.TimeoutException;
+
+import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
+import com.ning.billing.invoice.api.EmptyInvoiceEvent;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.jaxrs.json.SubscriptionJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+import com.ning.billing.jaxrs.util.KillbillEventHandler;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.userrequest.CompletionUserRequestBase;
+
+@Path(BaseJaxrsResource.SUBSCRIPTIONS_PATH)
+public class SubscriptionResource implements BaseJaxrsResource{
+
+    private static final Logger log = LoggerFactory.getLogger(SubscriptionResource.class);
+
+    private final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTime();
+
+    private final EntitlementUserApi entitlementApi;
+    private final Context context;
+    private final JaxrsUriBuilder uriBuilder;	
+    private final KillbillEventHandler killbillHandler;
+
+    @Inject
+    public SubscriptionResource(final JaxrsUriBuilder uriBuilder, final EntitlementUserApi entitlementApi,
+            final Clock clock, final Context context, final KillbillEventHandler killbillHandler) {
+        this.uriBuilder = uriBuilder;
+        this.entitlementApi = entitlementApi;
+        this.context = context;
+        this.killbillHandler = killbillHandler;
+    }
+
+    @GET
+    @Path("/{subscriptionId:" + UUID_PATTERN + "}")
+    @Produces(APPLICATION_JSON)
+    public Response getSubscription(@PathParam("subscriptionId") final String subscriptionId) {
+
+
+        UUID uuid = UUID.fromString(subscriptionId);
+        Subscription subscription = entitlementApi.getSubscriptionFromId(uuid);
+        if (subscription == null) {
+            return Response.status(Status.NO_CONTENT).build();
+        }
+        SubscriptionJson json = new SubscriptionJson(subscription, null, null, null);
+        return Response.status(Status.OK).entity(json).build();
+    }
+
+    @POST
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    public Response createSubscription(final SubscriptionJson subscription,
+            final @QueryParam(QUERY_REQUESTED_DT) String requestedDate,
+            final @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") Boolean callCompletion,
+            final @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") long timeoutSec) {
+
+
+        SubscriptionCallCompletionCallback<Subscription> callback = new SubscriptionCallCompletionCallback<Subscription>() {
+            @Override
+            public Subscription doOperation(final CallContext ctx) throws EntitlementUserApiException, InterruptedException, TimeoutException {
+
+                DateTime inputDate = (requestedDate != null) ? DATE_TIME_FORMATTER.parseDateTime(requestedDate) : null;        
+                UUID uuid = UUID.fromString(subscription.getBundleId());
+
+                PlanPhaseSpecifier spec =  new PlanPhaseSpecifier(subscription.getProductName(),
+                        ProductCategory.valueOf(subscription.getProductCategory()),
+                        BillingPeriod.valueOf(subscription.getBillingPeriod()), subscription.getPriceList(), null);
+                return entitlementApi.createSubscription(uuid, spec, inputDate, ctx);
+            }
+            @Override
+            public boolean isImmOperation() {
+                return true;
+            }
+            @Override
+            public Response doResponseOk(final Subscription createdSubscription) {
+                return uriBuilder.buildResponse(SubscriptionResource.class, "getSubscription", createdSubscription.getId());
+            }
+        };
+        SubscriptionCallCompletion<Subscription> callCompletionCreation = new SubscriptionCallCompletion<Subscription>();
+        return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion);
+    }
+
+    @PUT
+    @Produces(APPLICATION_JSON)
+    @Consumes(APPLICATION_JSON)
+    @Path("/{subscriptionId:" + UUID_PATTERN + "}")
+    public Response changeSubscriptionPlan(final SubscriptionJson subscription,
+            final @PathParam("subscriptionId") String subscriptionId,
+            final @QueryParam(QUERY_REQUESTED_DT) String requestedDate,
+            final @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") Boolean callCompletion,
+            final @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") long timeoutSec) {
+        
+        SubscriptionCallCompletionCallback<Response> callback = new SubscriptionCallCompletionCallback<Response>() {
+
+            private boolean isImmediateOp = true;
+            
+            @Override
+            public Response doOperation(CallContext ctx)
+                    throws EntitlementUserApiException, InterruptedException,
+                    TimeoutException {
+                UUID uuid = UUID.fromString(subscriptionId);
+                Subscription current = entitlementApi.getSubscriptionFromId(uuid);
+                if (current == null) {
+                    return Response.status(Status.NO_CONTENT).build();
+                }
+                DateTime inputDate = (requestedDate != null) ? DATE_TIME_FORMATTER.parseDateTime(requestedDate) : null;
+                isImmediateOp = current.changePlan(subscription.getProductName(),  BillingPeriod.valueOf(subscription.getBillingPeriod()), subscription.getPriceList(), inputDate, ctx);
+                return Response.status(Status.OK).build();
+            }
+            @Override
+            public boolean isImmOperation() {
+                return isImmediateOp;
+            }
+            @Override
+            public Response doResponseOk(Response operationResponse) {
+                if (operationResponse.getStatus() != Status.OK.getStatusCode()) {
+                    return operationResponse;
+                }
+                return getSubscription(subscriptionId);
+            }
+        };
+        SubscriptionCallCompletion<Response> callCompletionCreation = new SubscriptionCallCompletion<Response>();
+        return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion);
+    }
+    
+    @PUT
+    @Path("/{subscriptionId:" + UUID_PATTERN + "}/uncancel")
+    @Produces(APPLICATION_JSON)
+    public Response uncancelSubscriptionPlan(@PathParam("subscriptionId") String subscriptionId) {
+        try {
+            UUID uuid = UUID.fromString(subscriptionId);
+            Subscription current = entitlementApi.getSubscriptionFromId(uuid);
+            if (current == null) {
+                return Response.status(Status.NO_CONTENT).build();
+            }
+            current.uncancel(context.createContext());
+            return Response.status(Status.OK).build();
+        } catch (EntitlementUserApiException e) {
+            log.info(String.format("Failed to uncancel plan for subscription %s", subscriptionId), e);
+            return Response.status(Status.BAD_REQUEST).build();
+        }
+    }
+
+    @DELETE
+    @Path("/{subscriptionId:" + UUID_PATTERN + "}")
+    @Produces(APPLICATION_JSON)
+    public Response cancelSubscriptionPlan(final @PathParam("subscriptionId") String subscriptionId,
+            final @QueryParam(QUERY_REQUESTED_DT) String requestedDate,
+            final @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") Boolean callCompletion,
+            final @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") long timeoutSec) {
+        
+        SubscriptionCallCompletionCallback<Response> callback = new SubscriptionCallCompletionCallback<Response>() {
+
+            private boolean isImmediateOp = true;
+            
+            @Override
+            public Response doOperation(CallContext ctx)
+                    throws EntitlementUserApiException, InterruptedException,
+                    TimeoutException {
+                UUID uuid = UUID.fromString(subscriptionId);
+                Subscription current = entitlementApi.getSubscriptionFromId(uuid);
+                if (current == null) {
+                    return Response.status(Status.NO_CONTENT).build();
+                }
+                DateTime inputDate = (requestedDate != null) ? DATE_TIME_FORMATTER.parseDateTime(requestedDate) : null;
+                isImmediateOp = current.cancel(inputDate, false, ctx);
+                return Response.status(Status.OK).build();
+            }
+            @Override
+            public boolean isImmOperation() {
+                return isImmediateOp;
+            }
+            @Override
+            public Response doResponseOk(Response operationResponse) {
+                return operationResponse;
+            }
+        };
+        SubscriptionCallCompletion<Response> callCompletionCreation = new SubscriptionCallCompletion<Response>();
+        return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion);
+    }
+    
+    private final static class CompletionUserRequestSubscription extends CompletionUserRequestBase {
+
+        public CompletionUserRequestSubscription(final UUID userToken) {
+            super(userToken);
+        }
+        @Override
+        public void onSubscriptionTransition(SubscriptionEventTransition curEvent) {
+            log.info(String.format("Got event SubscriptionTransition token = %s, type = %s, remaining = %d ", 
+                    curEvent.getUserToken(), curEvent.getTransitionType(),  curEvent.getRemainingEventsForUserOperation())); 
+        }
+        @Override
+        public void onEmptyInvoice(final EmptyInvoiceEvent curEvent) {
+            log.info(String.format("Got event EmptyInvoiceNotification token = %s ", curEvent.getUserToken())); 
+            notifyForCompletion();
+        }
+        @Override
+        public void onInvoiceCreation(InvoiceCreationEvent curEvent) {
+            log.info(String.format("Got event InvoiceCreationNotification token = %s ", curEvent.getUserToken())); 
+            if (curEvent.getAmountOwed().compareTo(BigDecimal.ZERO) <= 0) {
+                notifyForCompletion();
+            }
+        }
+        @Override
+        public void onPaymentInfo(PaymentInfoEvent curEvent) {
+            log.info(String.format("Got event PaymentInfo token = %s ", curEvent.getUserToken()));  
+            notifyForCompletion();
+        }
+        @Override
+        public void onPaymentError(PaymentErrorEvent curEvent) {
+            log.info(String.format("Got event PaymentError token = %s ", curEvent.getUserToken())); 
+            notifyForCompletion();
+        }
+    }
+    
+    private interface SubscriptionCallCompletionCallback<T> {
+        public T doOperation(final CallContext ctx) throws EntitlementUserApiException, InterruptedException, TimeoutException;
+        public boolean isImmOperation();
+        public Response doResponseOk(final T operationResponse);
+    }
+
+    private class SubscriptionCallCompletion<T> {
+        
+        public Response withSynchronization(final SubscriptionCallCompletionCallback<T> callback, final long timeoutSec, final boolean callCompletion) {
+
+            CallContext ctx = context.createContext();
+            CompletionUserRequestSubscription waiter = callCompletion ? new CompletionUserRequestSubscription(ctx.getUserToken()) : null; 
+            try {
+                if (waiter != null) {
+                    killbillHandler.registerCompletionUserRequestWaiter(waiter);    
+                }
+                T operationValue = callback.doOperation(ctx);
+                if (waiter != null && callback.isImmOperation()) {
+                    waiter.waitForCompletion(timeoutSec * 1000);
+                }
+                return callback.doResponseOk(operationValue);
+            } catch (EntitlementUserApiException e) {
+                log.info(String.format("Failed to complete operation"), e);
+                return Response.status(Status.BAD_REQUEST).build();
+            } catch (InterruptedException e) {
+                return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+            } catch (TimeoutException e) {
+                return Response.status(Status.fromStatusCode(408)).build();   
+            } finally {
+                if (waiter != null) {
+                    killbillHandler.unregisterCompletionUserRequestWaiter(waiter);              
+                }
+            }
+        }
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java
new file mode 100644
index 0000000..cc19095
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+public class TagResource {
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
new file mode 100644
index 0000000..004a468
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.util;
+
+import java.util.UUID;
+
+import com.google.inject.Inject;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.UserType;
+
+public class Context {
+
+    private final CallOrigin origin;
+    private final UserType userType;
+    final CallContextFactory contextFactory;
+
+    @Inject
+    public Context(final CallContextFactory factory) {
+        super();
+        this.origin = CallOrigin.EXTERNAL;
+        this.userType = UserType.CUSTOMER;
+        this.contextFactory = factory;
+    }
+
+    // Simplistic until we decide how to populate that
+    public CallContext createContext() {
+        return contextFactory.createCallContext("Unknown", origin, userType, UUID.randomUUID());
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java
new file mode 100644
index 0000000..a38a9fe
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java
@@ -0,0 +1,39 @@
+/* 
+ * Copyright 2010-2011 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.jaxrs.util;
+
+import java.net.URI;
+import java.util.UUID;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+
+import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
+
+public class JaxrsUriBuilder {
+
+	
+	public Response buildResponse(final Class<? extends BaseJaxrsResource> theClass, final String getMethodName, final UUID objectId) {
+		URI uri = UriBuilder.fromPath(objectId.toString()).build();
+		Response.ResponseBuilder ri = Response.created(uri);
+		return ri.entity(new Object() {
+			@SuppressWarnings(value = "all")
+			public URI getUri() {
+				return UriBuilder.fromResource(theClass).path(theClass, getMethodName).build(objectId);
+			}
+		}).build();
+	}
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/KillbillEventHandler.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/KillbillEventHandler.java
new file mode 100644
index 0000000..7d835e8
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/KillbillEventHandler.java
@@ -0,0 +1,66 @@
+/* 
+ * Copyright 2010-2011 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.jaxrs.util;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.common.eventbus.Subscribe;
+import com.ning.billing.util.bus.BusEvent;
+import com.ning.billing.util.userrequest.CompletionUserRequest;
+import com.ning.billing.util.userrequest.CompletionUserRequestNotifier;
+import com.ning.billing.util.userrequest.CompletionUserRequestWaiter;
+
+public class KillbillEventHandler {
+    
+    
+    private final List<CompletionUserRequest> activeWaiters;
+    
+    public KillbillEventHandler() {
+        activeWaiters = new LinkedList<CompletionUserRequest>();
+    }
+    
+    public void registerCompletionUserRequestWaiter(final CompletionUserRequest waiter) {
+        if (waiter == null) {
+            return;
+        }
+        synchronized(activeWaiters) {
+            activeWaiters.add(waiter);
+        }
+    }
+    
+    public void unregisterCompletionUserRequestWaiter(final CompletionUserRequest waiter) {
+        if (waiter == null) {
+            return;
+        }
+        synchronized(activeWaiters) {
+            activeWaiters.remove(waiter);
+        }
+    }
+    
+    /*
+     * IRS event handler for killbill entitlement events
+     */
+    @Subscribe
+    public void handleEntitlementevents(final BusEvent event) {
+        if (activeWaiters.size() == 0) {
+            return;
+        }
+        for (CompletionUserRequestNotifier cur : activeWaiters) {
+            cur.onBusEvent(event);
+        }
+    }
+}
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestJsonViews.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestJsonViews.java
new file mode 100644
index 0000000..7e28130
--- /dev/null
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestJsonViews.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.io.StringWriter;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectWriter;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.ning.billing.jaxrs.json.SubscriptionJson.SubscriptionDeletedEventJson;
+import com.ning.billing.jaxrs.json.SubscriptionJson.SubscriptionNewEventJson;
+import com.ning.billing.jaxrs.json.SubscriptionJson.SubscriptionReadEventJson;
+
+public class TestJsonViews {
+
+
+    public static final Logger log = LoggerFactory.getLogger(TestJsonViews.class);
+
+    private ObjectMapper objectMapper;
+
+    @BeforeClass(groups="fast")
+    public void setup() {
+        objectMapper = new ObjectMapper().configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, false);
+        objectMapper.disable(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS);
+    }
+
+
+
+    @Test(groups="fast")
+    public void testSubscriptionBaseView() {
+        testSubscriptionView(BundleTimelineViews.Base.class);
+    }
+
+    @Test(groups="fast")
+    public void testSubscriptionTimelineView() {
+        testSubscriptionView(BundleTimelineViews.ReadTimeline.class);
+    }
+
+    private void testSubscriptionView(Class<? extends BundleTimelineViews.Base> viewClass) {
+        try {
+
+            SubscriptionJson obj = buildSubscriptionReadEventJson();
+
+            ObjectWriter objWriter = objectMapper.writerWithView(viewClass);
+
+            Writer writer = new StringWriter();
+            objWriter.writeValue(writer, obj);
+            String baseJson = writer.toString();
+
+            log.info(baseJson);
+
+            SubscriptionJson objFromJson = objectMapper.readValue(baseJson, SubscriptionJson.class);
+
+            log.info(objFromJson.toString());
+
+            if (viewClass.equals(BundleTimelineViews.Base.class)) {
+                Assert.assertNull(objFromJson.getEvents());
+            } else {
+                Assert.assertNotNull(objFromJson.getEvents());
+            }
+
+            writer = new StringWriter();
+            objWriter.writeValue(writer, objFromJson);
+            String newBaseJson = writer.toString();
+
+            Assert.assertEquals(newBaseJson, baseJson);
+
+        } catch (Exception e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    @Test(groups="fast")
+    public void testBundleReadTimelineJson() {
+        testBundleTimelineJson(BundleTimelineViews.ReadTimeline.class);
+    }
+
+    @Test(groups="fast")
+    public void testBundleWriteTimelineJson() {
+        testBundleTimelineJson(BundleTimelineViews.WriteTimeline.class);
+    }
+
+    private void testBundleTimelineJson(Class<? extends BundleTimelineViews.Base> viewClass) {
+
+        final boolean readTimeline = viewClass.equals(BundleTimelineViews.ReadTimeline.class);
+        try {
+
+            BundleTimelineJson obj = buildBundleTimelineJson(readTimeline);
+
+            ObjectWriter objWriter = objectMapper.writerWithView(viewClass);
+
+            Writer writer = new StringWriter();
+            objWriter.writeValue(writer, obj);
+            String baseJson = writer.toString();
+
+            log.info(baseJson);
+
+            BundleTimelineJson objFromJson = objectMapper.readValue(baseJson, BundleTimelineJson.class);
+
+            log.info(objFromJson.toString());
+
+            Assert.assertNotNull(objFromJson.getViewId());
+            Assert.assertNotNull(objFromJson.getBundle());
+
+            BundleJson bundle = objFromJson.getBundle();
+            Assert.assertNotNull(bundle.getBundleId());
+            Assert.assertNotNull(bundle.getAccountId());
+            Assert.assertNotNull(bundle.getExternalKey());
+            Assert.assertNotNull(bundle.getSubscriptions());
+
+            List<SubscriptionJson> subscriptions = bundle.getSubscriptions();
+            Assert.assertEquals(subscriptions.size(), 1);
+            SubscriptionJson sub = subscriptions.get(0);
+            Assert.assertNotNull(sub.getBundleId());
+            Assert.assertNotNull(sub.getBillingPeriod());
+            Assert.assertNotNull(sub.getPriceList());
+            Assert.assertNotNull(sub.getProductCategory());
+            Assert.assertNotNull(sub.getProductName());
+            Assert.assertNotNull(sub.getSubscriptionId());
+
+            List<SubscriptionReadEventJson> events = sub.getEvents();
+            List<SubscriptionDeletedEventJson> deletedEvents = sub.getDeletedEvents();
+            List<SubscriptionNewEventJson> newEvents = sub.getNewEvents();
+
+            if (viewClass.equals(BundleTimelineViews.WriteTimeline.class)) {
+                Assert.assertNull(objFromJson.getPayments());
+                Assert.assertNull(objFromJson.getInvoices());
+                Assert.assertNull(objFromJson.getInvoices());
+
+                Assert.assertNull(events);
+                Assert.assertEquals(newEvents.size(), 1);
+                for (SubscriptionNewEventJson cur : newEvents) {
+                    Assert.assertNotNull(cur.getRequestedDate());
+                    Assert.assertNotNull(cur.getEventType());
+                    Assert.assertNotNull(cur.getBillingPeriod());
+                    Assert.assertNotNull(cur.getPhase());
+                    Assert.assertNotNull(cur.getPriceList());
+                    Assert.assertNotNull(cur.getProduct());
+                }
+
+
+                Assert.assertEquals(deletedEvents.size(), 1);
+                for (SubscriptionDeletedEventJson cur : deletedEvents) {
+                    Assert.assertNotNull(cur.getEventId());
+                    Assert.assertNotNull(cur.getEffectiveDate());
+                    Assert.assertNotNull(cur.getRequestedDate());
+                    Assert.assertNotNull(cur.getEventType());
+                    Assert.assertNotNull(cur.getBillingPeriod());
+                    Assert.assertNotNull(cur.getPhase());
+                    Assert.assertNotNull(cur.getPriceList());
+                    Assert.assertNotNull(cur.getProduct());
+                }
+
+
+                Assert.assertNotNull(objFromJson.getResonForChange());
+
+            } else if (viewClass.equals(BundleTimelineViews.ReadTimeline.class)) {
+                Assert.assertNotNull(objFromJson.getPayments());
+                Assert.assertNotNull(objFromJson.getInvoices());
+                Assert.assertNotNull(objFromJson.getInvoices());
+
+                Assert.assertNull(newEvents);
+                Assert.assertNull(deletedEvents);
+                Assert.assertEquals(events.size(), 2);
+                for (SubscriptionReadEventJson cur : events) {
+                    Assert.assertNotNull(cur.getEventId());
+                    Assert.assertNotNull(cur.getEffectiveDate());
+                    Assert.assertNotNull(cur.getRequestedDate());
+                    Assert.assertNotNull(cur.getEventType());
+                    Assert.assertNotNull(cur.getBillingPeriod());
+                    Assert.assertNotNull(cur.getPhase());
+                    Assert.assertNotNull(cur.getPriceList());
+                    Assert.assertNotNull(cur.getProduct());
+                }
+
+                Assert.assertNull(objFromJson.getResonForChange());
+            } else {
+                Assert.fail("View of no interest");
+            }
+
+            writer = new StringWriter();
+            objWriter.writeValue(writer, objFromJson);
+            String newBaseJson = writer.toString();
+
+            Assert.assertEquals(newBaseJson, baseJson);
+
+        } catch (Exception e) {
+            Assert.fail(e.getMessage());
+        }
+
+    }
+
+    private BundleTimelineJson buildBundleTimelineJson(boolean readTimeline) {
+
+        final String reason = "whatever";
+        final String viewId = "view-123356";
+        final BundleJson bundle = buildBundle(readTimeline);
+        final List<PaymentJson> payments = new LinkedList<PaymentJson>();
+        payments.add(buildPaymentJson());
+
+        final List<InvoiceJson> invoices = new LinkedList<InvoiceJson>();
+        invoices.add(buildInvoiceJson());
+        return new BundleTimelineJson(viewId, bundle, payments, invoices, reason);
+    }
+
+
+    private BundleJson buildBundle(boolean readTimeline) {
+        final String bundleId = UUID.randomUUID().toString();
+        final String accountId = UUID.randomUUID().toString();
+        final String externalKey = "bozo-the-sioux";
+        final List<SubscriptionJson> subscriptions = new LinkedList<SubscriptionJson>();
+        subscriptions.add(readTimeline ? buildSubscriptionReadEventJson() : buildSubscriptionWriteEventJson());
+        return new BundleJson(bundleId, accountId, externalKey, subscriptions);
+    }
+    private PaymentJson buildPaymentJson() {
+
+        final BigDecimal paidAmount = new BigDecimal(128.56);
+        final String invoiceId = UUID.randomUUID().toString();
+        final String paymentId = UUID.randomUUID().toString();
+        final DateTime requestedDate =  new DateTime();
+        final DateTime effectiveDate = requestedDate;
+        final String status = "Success";
+        return new PaymentJson(paidAmount, invoiceId, paymentId, requestedDate, effectiveDate, status);
+    }
+
+    private InvoiceJson buildInvoiceJson() {
+        final BigDecimal amount = new BigDecimal(128.56);
+        final BigDecimal balance = new BigDecimal(0.0);
+        final String invoiceId = UUID.randomUUID().toString();
+        final String invoiceNumber =  "INV-00012";
+        final DateTime requestedDate =  new DateTime();
+        return new InvoiceJson(amount, invoiceId, requestedDate, invoiceNumber, balance);
+    }
+
+    private SubscriptionJson buildSubscriptionReadEventJson() {
+
+        final List<SubscriptionReadEventJson> events = new LinkedList<SubscriptionReadEventJson>();
+
+        final String eventId1 = UUID.randomUUID().toString();
+        final String productName1 = "gold";
+        final String billingPeriod1 = "monthly";
+        final DateTime requestedDate1 =  new DateTime();
+        final DateTime effectiveDate1 = requestedDate1;
+        final String priceList1 = "default";
+        final String eventType1 = "CREATE";
+        final String phase1 = "TRIAL";
+        SubscriptionReadEventJson ev1 = new SubscriptionReadEventJson(eventId1, billingPeriod1, requestedDate1, effectiveDate1, productName1, priceList1, eventType1, phase1);
+        events.add(ev1);
+
+        final String eventId2 = UUID.randomUUID().toString();
+        final String productName2 = "gold";
+        final String billingPeriod2 = "monthly";
+        final DateTime requestedDate2 =  new DateTime();
+        final DateTime effectiveDate2 = requestedDate2;
+        final String priceList2 = "default";
+        final String eventType2 = "PHASE";
+        final String phase2 = "EVERGREEN";
+        SubscriptionReadEventJson ev2 = new SubscriptionReadEventJson(eventId2, billingPeriod2, requestedDate2, effectiveDate2, productName2, priceList2, eventType2, phase2);
+        events.add(ev2);
+
+
+        final String subscriptionId = UUID.randomUUID().toString();
+        final String bundleId = UUID.randomUUID().toString();
+        final String productName = productName2;
+        final String productCategory = "classic";
+        final String billingPeriod = billingPeriod2;
+        final String priceList = priceList2;
+
+        SubscriptionJson obj = new SubscriptionJson(subscriptionId, bundleId, productName, productCategory, billingPeriod, priceList, events, null, null);
+        return obj;
+    }
+
+
+    private SubscriptionJson buildSubscriptionWriteEventJson() {
+
+        final List<SubscriptionNewEventJson> newEvents = new LinkedList<SubscriptionNewEventJson>();
+
+        final String eventId1 = UUID.randomUUID().toString();
+        final String productName1 = "gold";
+        final String billingPeriod1 = "monthly";
+        final DateTime requestedDate1 =  new DateTime();
+        final DateTime effectiveDate1 = requestedDate1;
+        final String priceList1 = "default";
+        final String eventType1 = "CREATE";
+        final String phase1 = "TRIAL";
+        SubscriptionNewEventJson ev1 = new SubscriptionNewEventJson(billingPeriod1, requestedDate1, productName1, priceList1, eventType1, phase1);
+        newEvents.add(ev1);
+
+        final List<SubscriptionDeletedEventJson> deletedEvents = new LinkedList<SubscriptionDeletedEventJson>();
+        final String eventId2 = UUID.randomUUID().toString();
+        final String productName2 = "gold";
+        final String billingPeriod2 = "monthly";
+        final DateTime requestedDate2 =  new DateTime();
+        final DateTime effectiveDate2 = requestedDate2;
+        final String priceList2 = "default";
+        final String eventType2 = "PHASE";
+        final String phase2 = "EVERGREEN";
+        SubscriptionDeletedEventJson ev2 = new SubscriptionDeletedEventJson(eventId2, billingPeriod2, requestedDate2, effectiveDate2, productName2, priceList2, eventType2, phase2);
+        deletedEvents.add(ev2);
+
+
+        final String subscriptionId = UUID.randomUUID().toString();
+        final String bundleId = UUID.randomUUID().toString();
+        final String productName = productName2;
+        final String productCategory = "classic";
+        final String billingPeriod = billingPeriod2;
+        final String priceList = priceList2;
+
+        SubscriptionJson obj = new SubscriptionJson(subscriptionId, bundleId, productName, productCategory, billingPeriod, priceList, null, newEvents, deletedEvents);
+        return obj;
+    }
+
+
+}
diff --git a/jaxrs/src/test/resources/log4j.xml b/jaxrs/src/test/resources/log4j.xml
new file mode 100644
index 0000000..512d2dc
--- /dev/null
+++ b/jaxrs/src/test/resources/log4j.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2010-2011 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.
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+        <param name="Target" value="System.out"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%p	%d{ISO8601}	%X{trace}	%t	%c	%m%n"/>
+        </layout>
+    </appender>
+
+
+    <logger name="com.ning.billing.jaxrs">
+        <level value="info"/>
+    </logger>
+
+    <root>
+        <priority value="info"/>
+        <appender-ref ref="stdout"/>
+    </root>
+</log4j:configuration>

ne/pom.xml 120(+120 -0)

diff --git a/ne/pom.xml b/ne/pom.xml
new file mode 100644
index 0000000..01c8700
--- /dev/null
+++ b/ne/pom.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 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</artifactId>
+        <version>0.1.11-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-ne</artifactId>
+    <name>killbill-ne</name>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-util</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.skife.config</groupId>
+            <artifactId>config-magic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>org.jdbi</groupId>
+            <artifactId>jdbi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-util</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-catalog</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-catalog</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-mxj</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-mxj-db-files</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!-- Strangely this is needed in order to run the tests in local db mode -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+           <scope>test</scope>
+         </dependency>
+ 
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <groups>fast,slow, stress</groups>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/ne/src/main/resources/com/ning/billing/ne/ddl.sql b/ne/src/main/resources/com/ning/billing/ne/ddl.sql
new file mode 100644
index 0000000..954a44f
--- /dev/null
+++ b/ne/src/main/resources/com/ning/billing/ne/ddl.sql
@@ -0,0 +1,9 @@
+
+DROP TABLE IF EXISTS overdue_states;
+CREATE TABLE overdue_states (
+  id char(36) NOT NULL,
+  state varchar(50) NOT NULL,
+  type varchar(20) NOT NULL,    
+  created_date datetime NOT NULL
+) ENGINE=innodb;
+CREATE INDEX overdue_states_by_id ON overdue_states (id);
\ No newline at end of file
diff --git a/ne/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java b/ne/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java
new file mode 100644
index 0000000..9cffbba
--- /dev/null
+++ b/ne/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2010-2011 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.entitlement.api.overdue;
+
+
+public class TestOverdueChecker {
+//
+//
+//    private static final String DISABLED_AND_BLOCKED_BUNDLE = "disabled-blocked-bundle";
+//    private static final String DISABLED_BUNDLE = "disabled-bundle";
+//    private static final String BLOCKED_BUNDLE = "blocked-bundle";
+//    private static final String CLEAR_BUNDLE = "clear-bundle";
+//    
+//        
+//    private static final DefaultOverdueState<SubscriptionBundle> CLEAR_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(CLEAR_BUNDLE, false, false); 
+//    private static final DefaultOverdueState<SubscriptionBundle> BLOCKED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(BLOCKED_BUNDLE, true, false);
+//    private static final DefaultOverdueState<SubscriptionBundle> DISABLED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_BUNDLE, false, true);
+//    private static final DefaultOverdueState<SubscriptionBundle> DISABLED_AND_BLOCKED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_AND_BLOCKED_BUNDLE, true, true) ;
+//   
+//    
+//    private OverdueChecker checker;
+//    private OverdueAccessApi overdueAccessApi;    
+//    private Subscription subscription;
+//    private SubscriptionBundle bundle;
+//    
+//    @BeforeClass(groups={"fast"})
+//    public void setup() {
+//        overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
+//        subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
+//        bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+//        ((ZombieControl) bundle).addResult("getAccountId", new UUID(0L,0L));
+//        ((ZombieControl) bundle).addResult("getId", new UUID(0L,0L));
+//        ((ZombieControl) bundle).addResult("getKey", "key");
+//        ((ZombieControl) subscription).addResult("getBundleId", new UUID(0L,0L));
+//       
+//        @SuppressWarnings("unchecked")
+//        final OverdueStatesBundle bundleODS =  new MockOverdueStatesBundle(new DefaultOverdueState[] {
+//                CLEAR_BUNDLE_STATE,BLOCKED_BUNDLE_STATE, DISABLED_BUNDLE_STATE, DISABLED_AND_BLOCKED_BUNDLE_STATE
+//        });
+//
+//        Injector i = Guice.createInjector(new AbstractModule() {
+//
+//            @Override
+//            protected void configure() {
+//                bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();
+//                CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
+//                ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog() {
+//
+//                    @Override
+//                    public void setOverdueRules() {
+//                         OverdueRules overdueRules = new MockOverdueRules().setOverdueStatesBundle(bundleODS);                       
+//                        setOverdueRules(overdueRules);  
+//                    }
+//                    
+//                });
+//                bind(CatalogService.class).toInstance(catalogService);
+//                
+//               
+//                bind(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
+//                bind(OverdueAccessApi.class).toInstance(overdueAccessApi);
+//                
+//                
+//                EntitlementDao entitlementDao = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementDao.class);
+//                //((ZombieControl) entitlementDao).addResult("", result)
+//                bind(EntitlementDao.class).toInstance(entitlementDao);
+//                ((ZombieControl) entitlementDao).addResult("getSubscriptionBundleFromId",bundle);
+//                
+//            }
+//            
+//        });
+//        checker = i.getInstance(OverdueChecker.class);
+//    }
+//
+//
+//    private void setStateBundle(OverdueState<SubscriptionBundle> state) {
+//        ((ZombieControl) bundle).addResult("getOverdueState", state);
+//    }
+//
+//    @Test(groups={"fast"}, enabled = true)
+//    public void testSubscriptionChecker() throws EntitlementUserApiException {
+//        setStateBundle(CLEAR_BUNDLE_STATE);
+//        checker.checkBlocked(bundle);
+//
+//        //BLOCKED BUNDLE
+//        try {
+//            setStateBundle(BLOCKED_BUNDLE_STATE);
+//            checker.checkBlocked(subscription);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//        
+//        //DISABLED BUNDLE
+//        try {
+//            setStateBundle(DISABLED_BUNDLE_STATE);
+//            checker.checkBlocked(subscription);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+// 
+//        try {
+//            setStateBundle(DISABLED_AND_BLOCKED_BUNDLE_STATE);
+//            checker.checkBlocked(subscription);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//        
+//         setStateBundle(CLEAR_BUNDLE_STATE);
+//        checker.checkBlocked(subscription);
+//        
+//    }
+//    
+//    @Test(groups={"fast"}, enabled = true)
+//    public void testBundleChecker() throws EntitlementUserApiException {
+//        setStateBundle(CLEAR_BUNDLE_STATE);
+//        checker.checkBlocked(bundle);
+//
+// 
+//        //BLOCKED BUNDLE
+//        try {
+//            setStateBundle(BLOCKED_BUNDLE_STATE);
+//            checker.checkBlocked(bundle);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//        
+//       
+//        //DISABLED BUNDLE
+//        try {
+//            setStateBundle(DISABLED_BUNDLE_STATE);
+//            checker.checkBlocked(bundle);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//
+//        //BLOCKED AND DISABLED BUNDLE
+//        try {
+//            setStateBundle(DISABLED_AND_BLOCKED_BUNDLE_STATE);
+//             checker.checkBlocked(bundle);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//
+//        setStateBundle(CLEAR_BUNDLE_STATE);
+//        checker.checkBlocked(bundle);
+//        
+//    }
+//    
+//
+//     
+}
diff --git a/ne/src/test/resources/log4j.xml b/ne/src/test/resources/log4j.xml
new file mode 100644
index 0000000..ac530a1
--- /dev/null
+++ b/ne/src/test/resources/log4j.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2010-2011 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.
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+        <param name="Target" value="System.out"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%p	%d{ISO8601}	%X{trace}	%t	%c	%m%n"/>
+        </layout>
+    </appender>
+
+
+    <logger name="com.ning.billing.entitlement">
+        <level value="info"/>
+    </logger>
+
+    <logger name="com.ning.billing.util.notificationq">
+        <level value="info"/>
+    </logger>
+
+    <root>
+        <priority value="info"/>
+        <appender-ref ref="stdout"/>
+    </root>
+</log4j:configuration>
diff --git a/ne/src/test/resources/resource.properties b/ne/src/test/resources/resource.properties
new file mode 100644
index 0000000..d63334b
--- /dev/null
+++ b/ne/src/test/resources/resource.properties
@@ -0,0 +1,7 @@
+killbill.catalog.uri=file:src/test/resources/catalogSample.xml
+killbill.entitlement.dao.claim.time=60000
+killbill.entitlement.dao.ready.max=1
+killbill.entitlement.engine.notifications.sleep=500
+user.timezone=UTC
+
+

overdue/pom.xml 6(+5 -1)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index 44f3149..c8a8ef8 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.8-SNAPSHOT</version>
+        <version>0.1.11-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>
@@ -28,6 +28,10 @@
             <groupId>com.ning.billing</groupId>
             <artifactId>killbill-util</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-ne</artifactId>
+        </dependency>
          <dependency>
             <groupId>com.google.inject</groupId>
             <artifactId>guice</artifactId>
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
index cbcbd9f..a7f0627 100644
--- a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
@@ -24,8 +24,9 @@ import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 import com.ning.billing.config.InvoiceConfig;
+import com.ning.billing.config.NotificationConfig;
+import com.ning.billing.ovedue.OverdueProperties;
 import com.ning.billing.overdue.service.DefaultOverdueService;
-import com.ning.billing.util.notificationq.NotificationConfig;
 import com.ning.billing.util.notificationq.NotificationQueue;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
@@ -38,14 +39,14 @@ public class DefaultOverdueCheckNotifier implements  OverdueCheckNotifier {
     public static final String OVERDUE_CHECK_NOTIFIER_QUEUE = "overdue-check-queue";
 
     private final NotificationQueueService notificationQueueService;
-	private final InvoiceConfig config;
+	private final OverdueProperties config;
 
     private NotificationQueue overdueQueue;
 	private final OverdueListener listener;
 
     @Inject
 	public DefaultOverdueCheckNotifier(NotificationQueueService notificationQueueService,
-			InvoiceConfig config, OverdueListener listener){
+	        OverdueProperties config, OverdueListener listener){
 		this.notificationQueueService = notificationQueueService;
 		this.config = config;
         this.listener = listener;
@@ -72,7 +73,7 @@ public class DefaultOverdueCheckNotifier implements  OverdueCheckNotifier {
             new NotificationConfig() {
                 @Override
                 public boolean isNotificationProcessingOff() {
-                    return config.isEventProcessingOff();
+                    return config.isNotificationProcessingOff();
                 }
                 @Override
                 public long getNotificationSleepTimeMs() {
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckPoster.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckPoster.java
index e6be7b1..29aa528 100644
--- a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckPoster.java
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckPoster.java
@@ -22,7 +22,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
-import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.overdue.config.api.Overdueable;
 import com.ning.billing.overdue.service.DefaultOverdueService;
 import com.ning.billing.util.notificationq.NotificationKey;
 import com.ning.billing.util.notificationq.NotificationQueue;
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java
index 8a0ad68..8573436 100644
--- a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java
@@ -19,7 +19,7 @@ package com.ning.billing.ovedue.notification;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
-import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.overdue.config.api.Overdueable;
 
 public interface OverdueCheckPoster {
 
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/OverdueProperties.java b/overdue/src/main/java/com/ning/billing/ovedue/OverdueProperties.java
new file mode 100644
index 0000000..4b38c09
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/OverdueProperties.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2011 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.ovedue;
+
+import org.skife.config.Config;
+import org.skife.config.Default;
+
+import com.ning.billing.config.KillbillConfig;
+import com.ning.billing.config.NotificationConfig;
+
+public interface OverdueProperties extends NotificationConfig, KillbillConfig  {
+
+    @Override
+    @Config("killbill.overdue.dao.claim.time")
+    @Default("60000")
+    public long getDaoClaimTimeMs();
+
+    @Override   
+    @Config("killbill.overdue.dao.ready.max")
+    @Default("10")
+    public int getDaoMaxReadyEvents();
+
+    @Override
+    @Config("killbill.overdue.engine.notifications.sleep")
+    @Default("500")
+    public long getNotificationSleepTimeMs();
+
+    @Override
+    @Config("killbill.notifications.off")
+    @Default("false")
+    public boolean isNotificationProcessingOff();
+
+    @Config("killbill.overdue.maxNumberOfMonthsInFuture")
+    @Default("36")
+    public int getNumberOfMonthsInFuture();
+
+    @Config("killbill.overdue.configUri")
+    @Default("jar:///com/ning/billing/irs/catalog/Catalog.xml")
+    public String getConfigURI();
+}
\ No newline at end of file
diff --git a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
index 1cd8e60..cffe754 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
@@ -23,13 +23,16 @@ import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.StaticCatalog;
-import com.ning.billing.catalog.api.overdue.BillingState;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.OverdueState;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
-import com.ning.billing.catalog.api.overdue.Overdueable;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.OverdueService;
 import com.ning.billing.overdue.OverdueUserApi;
+import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.OverdueStateSet;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.service.ExtendedOverdueService;
 import com.ning.billing.overdue.wrapper.OverdueWrapper;
 import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
 import com.ning.billing.util.overdue.OverdueAccessApi;
@@ -39,13 +42,13 @@ public class DefaultOverdueUserApi implements OverdueUserApi{
     
     private final OverdueWrapperFactory factory;
     private final OverdueAccessApi accessApi;
-    private final CatalogService catalogService;
+    private final OverdueConfig overdueConfig;
    
     @Inject
-    public DefaultOverdueUserApi(OverdueWrapperFactory factory, OverdueAccessApi accessApi,  CatalogService catalogService) {
+    public DefaultOverdueUserApi(OverdueWrapperFactory factory,OverdueAccessApi accessApi, ExtendedOverdueService service,  CatalogService catalogService) {
         this.factory = factory;
         this.accessApi = accessApi;
-        this.catalogService = catalogService;
+        this.overdueConfig = service.getOverdueConfig();
     }
     
     @SuppressWarnings("unchecked")
@@ -53,8 +56,7 @@ public class DefaultOverdueUserApi implements OverdueUserApi{
     public <T extends Overdueable> OverdueState<T> getOverdueStateFor(T overdueable) throws OverdueError {
         try {
             String stateName = accessApi.getOverdueStateNameFor(overdueable);
-            StaticCatalog catalog = catalogService.getCurrentCatalog();
-            OverdueStateSet<SubscriptionBundle> states = catalog.currentBundleOverdueStateSet();
+            OverdueStateSet<SubscriptionBundle> states = overdueConfig.getBundleStateSet();
             return (OverdueState<T>) states.findState(stateName);
         } catch (CatalogApiException e) {
             throw new OverdueError(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED,overdueable.getId(), overdueable.getClass().getSimpleName());
diff --git a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
index e9d3f77..28d3054 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -21,22 +21,22 @@ import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.OverdueState;
-import com.ning.billing.catalog.api.overdue.Overdueable;
-import com.ning.billing.overdue.dao.OverdueDao;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.overdue.OverdueAccessApi;
 
 public class OverdueStateApplicator<T extends Overdueable>{
 
-    private final OverdueDao overdueDao;
+    private final OverdueAccessApi accessApi;
     private final Clock clock;
 
 
 
     @Inject
-    public OverdueStateApplicator(OverdueDao overdueDao, Clock clock) {
-        this.overdueDao = overdueDao;
+    public OverdueStateApplicator(OverdueAccessApi accessApi, Clock clock) {
+        this.accessApi = accessApi;
         this.clock = clock;
     }
 
@@ -62,7 +62,7 @@ public class OverdueStateApplicator<T extends Overdueable>{
 
     protected void storeNewState(T overdueable, OverdueState<T> nextOverdueState) throws OverdueError {
         try {
-            overdueDao.setOverdueState(overdueable, nextOverdueState, Overdueable.Type.get(overdueable), clock);
+            accessApi.setOverrideState(overdueable, nextOverdueState, Overdueable.Type.get(overdueable), clock);
         } catch (Exception e) {
             throw new OverdueError(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, overdueable.getId(), overdueable.getClass().getName());
         }
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
index a5d66aa..eedde9a 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
@@ -27,10 +27,10 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
-import com.ning.billing.catalog.api.overdue.BillingState;
-import com.ning.billing.catalog.api.overdue.Overdueable;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.Overdueable;
 import com.ning.billing.util.clock.Clock;
 
 public abstract class BillingStateCalculator<T extends Overdueable> {
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
index 6705c30..544420f 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
@@ -28,14 +28,14 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
-import com.ning.billing.catalog.api.overdue.BillingStateBundle;
-import com.ning.billing.catalog.api.overdue.PaymentResponse;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 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.InvoiceItem;
 import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.overdue.config.api.BillingStateBundle;
+import com.ning.billing.overdue.config.api.PaymentResponse;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.tag.Tag;
 
diff --git a/overdue/src/main/java/com/ning/billing/overdue/exceptions/OverdueError.java b/overdue/src/main/java/com/ning/billing/overdue/exceptions/OverdueError.java
new file mode 100644
index 0000000..3959408
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/exceptions/OverdueError.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2011 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.overdue.exceptions;
+
+public class OverdueError extends Error {
+
+    private static final long serialVersionUID = 131398536;
+
+    public OverdueError() {
+        super();
+    }
+
+    public OverdueError(String msg, Throwable arg1) {
+        super(msg, arg1);
+    }
+
+    public OverdueError(String msg) {
+        super(msg);
+    }
+
+    public OverdueError(Throwable msg) {
+        super(msg);
+    }
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/glue/OverdueModule.java b/overdue/src/main/java/com/ning/billing/overdue/glue/OverdueModule.java
index 5797b1b..08fd53d 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/glue/OverdueModule.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/glue/OverdueModule.java
@@ -16,35 +16,15 @@
 
 package com.ning.billing.overdue.glue;
 
-import org.skife.jdbi.v2.IDBI;
-
 import com.google.inject.AbstractModule;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.ning.billing.overdue.dao.OverdueDao;
-import com.ning.billing.overdue.dao.OverdueSqlDao;
 
 public class OverdueModule extends AbstractModule {
-    
+
     @Override
     protected void configure() {
-        bind(OverdueDao.class).toProvider(OverdueDaoProvider.class);
-    }
-
-    public static class OverdueDaoProvider implements Provider<OverdueDao>{
+        // TODO Auto-generated method stub
         
-        private IDBI dbi;
-
-
-        @Inject
-        public OverdueDaoProvider(IDBI dbi){
-            this.dbi = dbi;
-        }
-        
-
-        @Override
-        public OverdueDao get() {
-            return dbi.onDemand(OverdueSqlDao.class);
-        }   
     }
+    
+
 }
diff --git a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
index 57c69d2..dd2bd86 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
@@ -16,17 +16,29 @@
 
 package com.ning.billing.overdue.service;
 
+import java.net.URI;
+
 import com.google.inject.Inject;
+import com.ning.billing.lifecycle.LifecycleHandlerType;
+import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
+import com.ning.billing.ovedue.OverdueProperties;
 import com.ning.billing.overdue.OverdueService;
 import com.ning.billing.overdue.OverdueUserApi;
+import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.util.config.XMLLoader;
 
-public class DefaultOverdueService implements OverdueService {
+public class DefaultOverdueService implements ExtendedOverdueService {
     public static final String OVERDUE_SERVICE_NAME = "overdue-service";
     private OverdueUserApi userApi;
+    private OverdueConfig overdueConfig;
+    private OverdueProperties properties;
+
+    private boolean isInitialized;
 
     @Inject
-    public DefaultOverdueService(OverdueUserApi userApi){
+    public DefaultOverdueService(OverdueUserApi userApi, OverdueProperties properties){
         this.userApi = userApi;
+        this.properties = properties;
     }
     
     @Override
@@ -39,5 +51,24 @@ public class DefaultOverdueService implements OverdueService {
         return userApi;
     }
 
-   
+    @Override
+   public OverdueConfig getOverdueConfig() {
+        return overdueConfig;
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
+    public synchronized void loadConfig() throws ServiceException {
+        if (!isInitialized) {
+            try {
+                System.out.println("Overdue config URI" + properties.getConfigURI());
+                URI u = new URI(properties.getConfigURI());
+                overdueConfig = XMLLoader.getObjectFromUri(u, OverdueConfig.class);
+
+                isInitialized = true;
+            } catch (Exception e) {
+                throw new ServiceException(e);
+            }
+        }
+    }
+
 }
diff --git a/overdue/src/main/java/com/ning/billing/overdue/service/ExtendedOverdueService.java b/overdue/src/main/java/com/ning/billing/overdue/service/ExtendedOverdueService.java
new file mode 100644
index 0000000..abcb38a
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/service/ExtendedOverdueService.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010-2011 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.overdue.service;
+
+import com.ning.billing.overdue.OverdueService;
+import com.ning.billing.overdue.config.OverdueConfig;
+
+public interface ExtendedOverdueService extends OverdueService {
+
+    public OverdueConfig getOverdueConfig();
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
index f110d75..56e5b71 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
@@ -17,13 +17,13 @@
 package com.ning.billing.overdue.wrapper;
 
 import com.ning.billing.catalog.api.CatalogApiException;
-import com.ning.billing.catalog.api.overdue.BillingState;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.OverdueState;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
-import com.ning.billing.catalog.api.overdue.Overdueable;
 import com.ning.billing.overdue.applicator.OverdueStateApplicator;
 import com.ning.billing.overdue.calculator.BillingStateCalculator;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.OverdueStateSet;
+import com.ning.billing.overdue.config.api.Overdueable;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.overdue.OverdueAccessApi;
 
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
index 1df769d..681e171 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
@@ -18,46 +18,41 @@ package com.ning.billing.overdue.wrapper;
 
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.api.CatalogApiException;
-import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.Overdueable;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.overdue.applicator.OverdueStateApplicator;
 import com.ning.billing.overdue.calculator.BillingStateCalculatorBundle;
+import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.service.ExtendedOverdueService;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.overdue.OverdueAccessApi;
 
 public class OverdueWrapperFactory {
 
-    private final CatalogService catalogService;
+    private final OverdueConfig overdueConfig;
     private final BillingStateCalculatorBundle billingStateCalcuatorBundle;
     private final OverdueStateApplicator<SubscriptionBundle> overdueStateApplicatorBundle;
     private final OverdueAccessApi api;
     private final Clock clock;
 
     @Inject
-    public OverdueWrapperFactory(OverdueAccessApi api, CatalogService catalogService, Clock clock, 
+    public OverdueWrapperFactory(OverdueAccessApi api, ExtendedOverdueService service, Clock clock, 
             BillingStateCalculatorBundle billingStateCalcuatorBundle, OverdueStateApplicator<SubscriptionBundle> overdueStateApplicatorBundle) {
         this.billingStateCalcuatorBundle = billingStateCalcuatorBundle;
         this.overdueStateApplicatorBundle = overdueStateApplicatorBundle;
-        this.catalogService = catalogService;
+        this.overdueConfig = service.getOverdueConfig();
         this.api = api;
         this.clock = clock;
     }
 
     @SuppressWarnings("unchecked")
     public <T extends Overdueable> OverdueWrapper<T> createOverdueWrapperFor(T overdueable) throws OverdueError {
-        try {
-            if(overdueable instanceof SubscriptionBundle) {
-                return (OverdueWrapper<T>)new OverdueWrapper<SubscriptionBundle>((SubscriptionBundle)overdueable, api, catalogService.getCurrentCatalog().currentBundleOverdueStateSet(), 
-                        clock, billingStateCalcuatorBundle, overdueStateApplicatorBundle );
-            } else {
-                throw new OverdueError(ErrorCode.OVERDUE_OVERDUEABLE_NOT_SUPPORTED, overdueable.getClass());
-            }
-
-        } catch (CatalogApiException e) {
-            throw new OverdueError(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, overdueable.getId().toString(), overdueable.getClass().toString());
+        if(overdueable instanceof SubscriptionBundle) {
+            return (OverdueWrapper<T>)new OverdueWrapper<SubscriptionBundle>((SubscriptionBundle)overdueable, api, overdueConfig.getBundleStateSet(), 
+                    clock, billingStateCalcuatorBundle, overdueStateApplicatorBundle );
+        } else {
+            throw new OverdueError(ErrorCode.OVERDUE_OVERDUEABLE_NOT_SUPPORTED, overdueable.getClass());
         }
     }
 
diff --git a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculator.java b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculator.java
index 8d2a525..db9ab74 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculator.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculator.java
@@ -27,13 +27,13 @@ import org.joda.time.DateTime;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.ning.billing.catalog.api.overdue.BillingState;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoiceUserApi;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.overdue.config.api.BillingState;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 
diff --git a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
index 6374ce1..3d5b855 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
@@ -30,8 +30,6 @@ import com.ning.billing.catalog.MockPlan;
 import com.ning.billing.catalog.MockPriceList;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PriceList;
-import com.ning.billing.catalog.api.overdue.BillingStateBundle;
-import com.ning.billing.catalog.api.overdue.PaymentResponse;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
@@ -40,6 +38,8 @@ import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoiceUserApi;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.overdue.config.api.BillingStateBundle;
+import com.ning.billing.overdue.config.api.PaymentResponse;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/CreateOverdueConfigSchema.java b/overdue/src/test/java/com/ning/billing/overdue/config/CreateOverdueConfigSchema.java
new file mode 100644
index 0000000..bbd4b18
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/CreateOverdueConfigSchema.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2011 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.overdue.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.Writer;
+
+import com.ning.billing.util.config.XMLSchemaGenerator;
+
+public class CreateOverdueConfigSchema {
+
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) throws Exception {
+		if(args.length != 1) {
+			System.err.println("Usage: <filepath>");
+			System.exit(0);
+		}
+		
+		File f = new File(args[0]);
+		Writer w = new FileWriter(f);
+		w.write(XMLSchemaGenerator.xmlSchemaAsString(OverdueConfig.class));
+		w.close();
+
+	}
+
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/io/TestReadConfig.java b/overdue/src/test/java/com/ning/billing/overdue/config/io/TestReadConfig.java
new file mode 100644
index 0000000..76cd152
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/io/TestReadConfig.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2011 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.overdue.config.io;
+
+import org.testng.annotations.Test;
+
+import com.google.common.io.Resources;
+import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.util.config.XMLLoader;
+
+public class TestReadConfig {
+    @Test(enabled=false) //TODO MDW whilst refactoring
+    public void testConfigLoad() throws Exception {
+        XMLLoader.getObjectFromString(Resources.getResource("OverdueConfig.xml").toExternalForm(), OverdueConfig.class);
+    }
+
+}
diff --git a/overdue/src/test/resources/OverdueConfig.xml b/overdue/src/test/resources/OverdueConfig.xml
new file mode 100644
index 0000000..6318e8d
--- /dev/null
+++ b/overdue/src/test/resources/OverdueConfig.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 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. -->
+
+<overdueRules xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+	<bundleOverdueStates>
+		<state name="Clear">
+			<isClearState>true</isClearState>
+		</state>
+	</bundleOverdueStates>
+</overdueRules>
+
+    
\ No newline at end of file
diff --git a/overdue/src/test/resources/OverdueConfigSchema.xsd b/overdue/src/test/resources/OverdueConfigSchema.xsd
new file mode 100644
index 0000000..36379ef
--- /dev/null
+++ b/overdue/src/test/resources/OverdueConfigSchema.xsd
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
+<xs:element name="overdue" type="overdueRules"/>
+<xs:complexType name="overdueRules">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence>
+<xs:element name="bundleOverdueStates" type="overdueStatesBundle"/>
+</xs:sequence>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType abstract="true" name="validatingConfig">
+<xs:sequence/>
+</xs:complexType>
+<xs:complexType name="overdueStatesBundle">
+<xs:complexContent>
+<xs:extension base="defaultOverdueStateSet">
+<xs:sequence>
+<xs:element maxOccurs="unbounded" name="state" type="defaultOverdueState"/>
+</xs:sequence>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType abstract="true" name="defaultOverdueStateSet">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence/>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType name="defaultOverdueState">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence>
+<xs:element minOccurs="0" name="condition" type="defaultCondition"/>
+<xs:element minOccurs="0" name="externalMessage" type="xs:string"/>
+<xs:element minOccurs="0" name="disableEntitlementAndChangesBlocked" type="xs:boolean"/>
+<xs:element minOccurs="0" name="blockChanges" type="xs:boolean"/>
+<xs:element minOccurs="0" name="daysBetweenPaymentRetries" type="xs:int"/>
+<xs:element minOccurs="0" name="isClearState" type="xs:boolean"/>
+</xs:sequence>
+<xs:attribute name="name" type="xs:ID" use="required"/>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType name="defaultCondition">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence>
+<xs:element minOccurs="0" name="numberOfUnpaidInvoicesEqualsOrExceeds" type="xs:int"/>
+<xs:element minOccurs="0" name="totalUnpaidInvoiceBalanceEqualsOrExceeds" type="xs:decimal"/>
+<xs:element minOccurs="0" name="timeSinceEarliestUnpaidInvoiceEqualsOrExceeds" type="defaultDuration"/>
+<xs:element minOccurs="0" name="responseForLastFailedPaymentIn">
+<xs:complexType>
+<xs:sequence>
+<xs:element maxOccurs="unbounded" minOccurs="0" name="response" type="paymentResponse"/>
+</xs:sequence>
+</xs:complexType>
+</xs:element>
+<xs:element minOccurs="0" name="controlTag" type="controlTagType"/>
+</xs:sequence>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType name="defaultDuration">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence>
+<xs:element name="unit" type="timeUnit"/>
+<xs:element minOccurs="0" name="number" type="xs:int"/>
+</xs:sequence>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:simpleType name="timeUnit">
+<xs:restriction base="xs:string">
+<xs:enumeration value="DAYS"/>
+<xs:enumeration value="MONTHS"/>
+<xs:enumeration value="YEARS"/>
+<xs:enumeration value="UNLIMITED"/>
+</xs:restriction>
+</xs:simpleType>
+<xs:simpleType name="paymentResponse">
+<xs:restriction base="xs:string">
+<xs:enumeration value="INVALID_CARD"/>
+<xs:enumeration value="EXPIRED_CARD"/>
+<xs:enumeration value="LOST_OR_STOLEN_CARD"/>
+<xs:enumeration value="DO_NOT_HONOR"/>
+<xs:enumeration value="INSUFFICIENT_FUNDS"/>
+<xs:enumeration value="DECLINE"/>
+<xs:enumeration value="PROCESSING_ERROR"/>
+<xs:enumeration value="INVALID_AMOUNT"/>
+<xs:enumeration value="DUPLICATE_TRANSACTION"/>
+<xs:enumeration value="OTHER"/>
+</xs:restriction>
+</xs:simpleType>
+<xs:simpleType name="controlTagType">
+<xs:restriction base="xs:string">
+<xs:enumeration value="AUTO_PAY_OFF"/>
+<xs:enumeration value="AUTO_INVOICING_OFF"/>
+<xs:enumeration value="OVERDUE_ENFORCEMENT_OFF"/>
+<xs:enumeration value="WRITTEN_OFF"/>
+</xs:restriction>
+</xs:simpleType>
+</xs:schema>
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index 6031600..0d9c19a 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
 import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.config.PaymentConfig;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.invoice.model.DefaultInvoicePayment;
@@ -38,7 +39,6 @@ import com.ning.billing.payment.RetryService;
 import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.payment.provider.PaymentProviderPlugin;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
-import com.ning.billing.payment.setup.PaymentConfig;
 import com.ning.billing.util.callcontext.CallContext;
 
 public class DefaultPaymentApi implements PaymentApi {
@@ -68,7 +68,7 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentError, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId) {
+    public Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.getPaymentMethodInfo(paymentMethodId);
     }
@@ -97,51 +97,51 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentError, List<PaymentMethodInfo>> getPaymentMethods(String accountKey) {
+    public Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.getPaymentMethods(accountKey);
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentGateway(String accountKey, CallContext context) {
+    public Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.updatePaymentGateway(accountKey);
     }
 
     @Override
-    public Either<PaymentError, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
+    public Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.getPaymentProviderAccount(accountKey);
     }
 
     @Override
-    public Either<PaymentError, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context) {
+    public Either<PaymentErrorEvent, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.addPaymentMethod(accountKey, paymentMethod);
     }
 
     @Override
-    public Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context) {
+    public Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.deletePaymentMethod(accountKey, paymentMethodId);
     }
 
     @Override
-    public Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context) {
+    public Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.updatePaymentMethod(accountKey, paymentMethodInfo);
     }
 
     @Override
-    public List<Either<PaymentError, PaymentInfo>> createPayment(String accountKey, List<String> invoiceIds, CallContext context) {
+    public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(String accountKey, List<String> invoiceIds, CallContext context) {
         final Account account = accountUserApi.getAccountByKey(accountKey);
         return createPayment(account, invoiceIds, context);
     }
 
     @Override
-    public Either<PaymentError, PaymentInfo> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context) {
+    public Either<PaymentErrorEvent, PaymentInfoEvent> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context) {
+        
         PaymentAttempt paymentAttempt = paymentDao.getPaymentAttemptById(paymentAttemptId);
-
         if (paymentAttempt != null) {
             Invoice invoice = invoicePaymentApi.getInvoice(paymentAttempt.getInvoiceId());
             Account account = accountUserApi.getAccountById(paymentAttempt.getAccountId());
@@ -150,10 +150,11 @@ public class DefaultPaymentApi implements PaymentApi {
                 if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0 ) {
                     // TODO: send a notification that invoice was ignored?
                     log.info("Received invoice for payment with outstanding amount of 0 {} ", invoice);
-                    return Either.left(new PaymentError("invoice_balance_0",
-                                                        "Invoice balance was 0 or less",
-                                                        paymentAttempt.getAccountId(),
-                                                        paymentAttempt.getInvoiceId()));
+                    return Either.left((PaymentErrorEvent) new DefaultPaymentError("invoice_balance_0",
+                            "Invoice balance was 0 or less",
+                            paymentAttempt.getAccountId(),
+                            paymentAttempt.getInvoiceId(),
+                            context.getUserToken()));
                 }
                 else {
                     PaymentAttempt newPaymentAttempt = new PaymentAttempt.Builder(paymentAttempt)
@@ -166,31 +167,32 @@ public class DefaultPaymentApi implements PaymentApi {
                 }
             }
         }
-        return Either.left(new PaymentError("retry_payment_error",
-                                            "Could not load payment attempt, invoice or account for id " + paymentAttemptId,
-                                            paymentAttempt.getAccountId(),
-                                            paymentAttempt.getInvoiceId()));
+        return Either.left((PaymentErrorEvent) new DefaultPaymentError("retry_payment_error",
+                "Could not load payment attempt, invoice or account for id " + paymentAttemptId,
+                paymentAttempt.getAccountId(),
+                paymentAttempt.getInvoiceId(),
+                context.getUserToken()));
     }
 
     @Override
-    public List<Either<PaymentError, PaymentInfo>> createPayment(Account account, List<String> invoiceIds, CallContext context) {
+    public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(Account account, List<String> invoiceIds, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
 
-        List<Either<PaymentError, PaymentInfo>> processedPaymentsOrErrors = new ArrayList<Either<PaymentError, PaymentInfo>>(invoiceIds.size());
+        List<Either<PaymentErrorEvent, PaymentInfoEvent>> processedPaymentsOrErrors = new ArrayList<Either<PaymentErrorEvent, PaymentInfoEvent>>(invoiceIds.size());
 
         for (String invoiceId : invoiceIds) {
             Invoice invoice = invoicePaymentApi.getInvoice(UUID.fromString(invoiceId));
 
             if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0 ) {
                 log.debug("Received invoice for payment with balance of 0 {} ", invoice);
-
             }
             else if (invoice.isMigrationInvoice()) {
             	log.info("Received invoice for payment that is a migration invoice - don't know how to handle those yet: {}", invoice);
-            	Either<PaymentError, PaymentInfo> result = Either.left(new PaymentError("migration invoice",
+            	Either<PaymentErrorEvent, PaymentInfoEvent> result = Either.left((PaymentErrorEvent) new DefaultPaymentError("migration invoice",
                         "Invoice balance was a migration invoice",
                         account.getId(),
-                        UUID.fromString(invoiceId)));
+                        UUID.fromString(invoiceId),
+                        context.getUserToken()));
             			processedPaymentsOrErrors.add(result);
             }
             else {
@@ -203,13 +205,13 @@ public class DefaultPaymentApi implements PaymentApi {
         return processedPaymentsOrErrors;
     }
 
-    private Either<PaymentError, PaymentInfo> processPayment(PaymentProviderPlugin plugin, Account account, Invoice invoice,
+    private Either<PaymentErrorEvent, PaymentInfoEvent> processPayment(PaymentProviderPlugin plugin, Account account, Invoice invoice,
                                                              PaymentAttempt paymentAttempt, CallContext context) {
-        Either<PaymentError, PaymentInfo> paymentOrError = plugin.processInvoice(account, invoice);
-        PaymentInfo paymentInfo = null;
+        Either<PaymentErrorEvent, PaymentInfoEvent> paymentOrError = plugin.processInvoice(account, invoice);
+        PaymentInfoEvent paymentInfo = null;
 
         if (paymentOrError.isLeft()) {
-            String error = StringUtils.substring(paymentOrError.getLeft().getMessage() + paymentOrError.getLeft().getType(), 0, 100);
+            String error = StringUtils.substring(paymentOrError.getLeft().getMessage() + paymentOrError.getLeft().getBusEventType(), 0, 100);
             log.info("Could not process a payment for " + paymentAttempt + " error was " + error);
 
             scheduleRetry(paymentAttempt, error);
@@ -220,7 +222,7 @@ public class DefaultPaymentApi implements PaymentApi {
 
             final String paymentMethodId = paymentInfo.getPaymentMethodId();
             log.debug("Fetching payment method info for payment method id " + ((paymentMethodId == null) ? "null" : paymentMethodId));
-            Either<PaymentError, PaymentMethodInfo> paymentMethodInfoOrError = plugin.getPaymentMethodInfo(paymentMethodId);
+            Either<PaymentErrorEvent, PaymentMethodInfo> paymentMethodInfoOrError = plugin.getPaymentMethodInfo(paymentMethodId);
 
             if (paymentMethodInfoOrError.isRight()) {
                 PaymentMethodInfo paymentMethodInfo = paymentMethodInfoOrError.getRight();
@@ -285,13 +287,13 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentError, String> createPaymentProviderAccount(Account account, CallContext context) {
+    public Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin((Account)null);
         return plugin.createPaymentProviderAccount(account);
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentProviderAccountContact(String externalKey, CallContext context) {
+    public Either<PaymentErrorEvent, Void> updatePaymentProviderAccountContact(String externalKey, CallContext context) {
     	Account account = accountUserApi.getAccountByKey(externalKey);
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
         return plugin.updatePaymentProviderAccountExistingContact(account);
@@ -303,7 +305,7 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public List<Either<PaymentError, PaymentInfo>> createRefund(Account account,
+    public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createRefund(Account account,
                                                                 List<String> invoiceIds,
                                                                 CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
@@ -311,7 +313,7 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public List<PaymentInfo> getPaymentInfo(List<String> invoiceIds) {
+    public List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds) {
         return paymentDao.getPaymentInfo(invoiceIds);
     }
 
@@ -321,7 +323,7 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public PaymentInfo getPaymentInfoForPaymentAttemptId(String paymentAttemptId) {
+    public PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptId) {
         return paymentDao.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
     }
 
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
index bcdda9a..a21a90c 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
@@ -29,7 +29,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import org.skife.jdbi.v2.Transaction;
 import org.skife.jdbi.v2.TransactionStatus;
 
@@ -87,7 +87,7 @@ public class AuditedPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void savePaymentInfo(final PaymentInfo info, final CallContext context) {
+    public void savePaymentInfo(final PaymentInfoEvent info, final CallContext context) {
         sqlDao.inTransaction(new Transaction<Void, PaymentSqlDao>() {
             @Override
             public Void inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
@@ -128,7 +128,7 @@ public class AuditedPaymentDao implements PaymentDao {
             @Override
             public Void inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
                 transactional.updatePaymentInfo(type, paymentId, cardType, cardCountry, context);
-                PaymentInfo paymentInfo = transactional.getPaymentInfo(paymentId);
+                PaymentInfoEvent paymentInfo = transactional.getPaymentInfo(paymentId);
                 UUID historyRecordId = UUID.randomUUID();
                 transactional.insertPaymentInfoHistory(historyRecordId.toString(), paymentInfo, context);
                 AuditSqlDao auditSqlDao = transactional.become(AuditSqlDao.class);
@@ -141,9 +141,9 @@ public class AuditedPaymentDao implements PaymentDao {
     }
 
     @Override
-    public List<PaymentInfo> getPaymentInfo(List<String> invoiceIds) {
+    public List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds) {
         if (invoiceIds == null || invoiceIds.size() == 0) {
-            return ImmutableList.<PaymentInfo>of();
+            return ImmutableList.<PaymentInfoEvent>of();
         } else {
             return sqlDao.getPaymentInfos(invoiceIds);
         }
@@ -164,7 +164,7 @@ public class AuditedPaymentDao implements PaymentDao {
     }
 
     @Override
-    public PaymentInfo getPaymentInfoForPaymentAttemptId(String paymentAttemptIdStr) {
+    public PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptIdStr) {
         return sqlDao.getPaymentInfoForPaymentAttemptId(paymentAttemptIdStr);
     }
 
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
index ce6adf6..8c07824 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
@@ -21,7 +21,7 @@ import java.util.UUID;
 
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.util.callcontext.CallContext;
 
 public interface PaymentDao {
@@ -29,7 +29,7 @@ public interface PaymentDao {
     PaymentAttempt createPaymentAttempt(Invoice invoice, CallContext context);
     PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt, CallContext context);
 
-    void savePaymentInfo(PaymentInfo right, CallContext context);
+    void savePaymentInfo(PaymentInfoEvent right, CallContext context);
 
     PaymentAttempt getPaymentAttemptForPaymentId(String paymentId);
     List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(List<String> invoiceIds);
@@ -40,8 +40,8 @@ public interface PaymentDao {
 
     void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry, CallContext context);
 
-    List<PaymentInfo> getPaymentInfo(List<String> invoiceIds);
+    List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds);
 
     PaymentAttempt getPaymentAttemptById(UUID paymentAttemptId);
-    PaymentInfo getPaymentInfoForPaymentAttemptId(String paymentAttemptId);
+    PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptId);
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
index 96d7e0b..2748111 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
@@ -42,8 +42,9 @@ import org.skife.jdbi.v2.tweak.ResultSetMapper;
 import org.skife.jdbi.v2.unstable.BindIn;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.api.DefaultPaymentInfo;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 
 @ExternalizedSqlViaStringTemplate3()
 @RegisterMapper({PaymentSqlDao.PaymentAttemptMapper.class, PaymentSqlDao.PaymentInfoMapper.class})
@@ -70,7 +71,7 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
     List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(@BindIn("invoiceIds") List<String> invoiceIds);
 
     @SqlQuery
-    PaymentInfo getPaymentInfoForPaymentAttemptId(@Bind("payment_attempt_id") String paymentAttemptId);
+    PaymentInfoEvent getPaymentInfoForPaymentAttemptId(@Bind("payment_attempt_id") String paymentAttemptId);
 
     @SqlUpdate
     void updatePaymentAttemptWithPaymentId(@Bind("payment_attempt_id") String paymentAttemptId,
@@ -90,19 +91,19 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
                            @CallContextBinder CallContext context);
 
     @SqlQuery
-    List<PaymentInfo> getPaymentInfos(@BindIn("invoiceIds") final List<String> invoiceIds);
+    List<PaymentInfoEvent> getPaymentInfos(@BindIn("invoiceIds") final List<String> invoiceIds);
 
     @SqlUpdate
-    void insertPaymentInfo(@Bind(binder = PaymentInfoBinder.class) final PaymentInfo paymentInfo,
+    void insertPaymentInfo(@Bind(binder = PaymentInfoBinder.class) final PaymentInfoEvent paymentInfo,
                            @CallContextBinder final CallContext context);
 
     @SqlUpdate
     void insertPaymentInfoHistory(@Bind("historyRecordId") final String historyRecordId,
-                                  @Bind(binder = PaymentInfoBinder.class) final PaymentInfo paymentInfo,
+                                  @Bind(binder = PaymentInfoBinder.class) final PaymentInfoEvent paymentInfo,
                                   @CallContextBinder final CallContext context);
 
     @SqlQuery
-    PaymentInfo getPaymentInfo(@Bind("paymentId") final String paymentId);
+    PaymentInfoEvent getPaymentInfo(@Bind("paymentId") final String paymentId);
 
     public static final class PaymentAttemptBinder extends BinderBase implements Binder<Bind, PaymentAttempt> {
         @Override
@@ -151,9 +152,9 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
         }
     }
 
-    public static final class PaymentInfoBinder extends BinderBase implements Binder<Bind, PaymentInfo> {
+    public static final class PaymentInfoBinder extends BinderBase implements Binder<Bind, PaymentInfoEvent> {
         @Override
-        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentInfo paymentInfo) {
+        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentInfoEvent paymentInfo) {
             stmt.bind("payment_id", paymentInfo.getPaymentId().toString());
             stmt.bind("amount", paymentInfo.getAmount());
             stmt.bind("refund_amount", paymentInfo.getRefundAmount());
@@ -172,9 +173,9 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
         }
     }
 
-    public static class PaymentInfoMapper extends MapperBase implements ResultSetMapper<PaymentInfo> {
+    public static class PaymentInfoMapper extends MapperBase implements ResultSetMapper<PaymentInfoEvent> {
         @Override
-        public PaymentInfo map(int index, ResultSet rs, StatementContext ctx) throws SQLException {
+        public PaymentInfoEvent map(int index, ResultSet rs, StatementContext ctx) throws SQLException {
 
             String paymentId = rs.getString("payment_id");
             BigDecimal amount = rs.getBigDecimal("amount");
@@ -187,12 +188,14 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
             String paymentMethodId = rs.getString("payment_method_id");
             String paymentMethod = rs.getString("payment_method");
             String cardType = rs.getString("card_type");
-            String cardCountry = rs.getString("card_country");
+            String cardCountry = rs.getString("card_country");            
             DateTime effectiveDate = getDate(rs, "effective_dt");
             DateTime createdDate = getDate(rs, "created_dt");
             DateTime updatedDate = getDate(rs, "updated_dt");
 
-            return new PaymentInfo(paymentId,
+            UUID userToken = null; //rs.getString("user_token") != null ? UUID.fromString(rs.getString("user_token")) : null;
+            
+            return new DefaultPaymentInfo(paymentId,
                                    amount,
                                    refundAmount,
                                    bankIdentificationNumber,
@@ -204,6 +207,7 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
                                    paymentMethod,
                                    cardType,
                                    cardCountry,
+                                   userToken,
                                    effectiveDate,
                                    createdDate,
                                    updatedDate);
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
index a23a4f7..8e28b80 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
@@ -25,17 +25,19 @@ import org.joda.time.DateTimeZone;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.payment.api.DefaultPaymentError;
+import com.ning.billing.payment.api.DefaultPaymentInfo;
 import com.ning.billing.payment.api.Either;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentMethodInfo;
 import com.ning.billing.payment.api.PaymentProviderAccount;
 
 public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
 
     @Override
-    public Either<PaymentError, PaymentInfo> processInvoice(Account account, Invoice invoice) {
-        PaymentInfo payment = new PaymentInfo.Builder()
+    public Either<PaymentErrorEvent, PaymentInfoEvent> processInvoice(Account account, Invoice invoice) {
+        PaymentInfoEvent payment = new DefaultPaymentInfo.Builder()
                                              .setPaymentId(UUID.randomUUID().toString())
                                              .setAmount(invoice.getBalance())
                                              .setStatus("Processed")
@@ -47,25 +49,25 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public Either<PaymentError, PaymentInfo> getPaymentInfo(String paymentId) {
+    public Either<PaymentErrorEvent, PaymentInfoEvent> getPaymentInfo(String paymentId) {
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, String> createPaymentProviderAccount(Account account) {
-        return Either.left(new PaymentError("unsupported",
+    public Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account) {
+        return Either.left((PaymentErrorEvent) new DefaultPaymentError("unsupported",
                                             "Account creation not supported in this plugin",
                                             account.getId(),
-                                            null));
+                                            null, null));
     }
 
     @Override
-    public Either<PaymentError, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
+    public Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, String> addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
+    public Either<PaymentErrorEvent, String> addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
         return Either.right(null);
     }
 
@@ -74,42 +76,42 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
+    public Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
         return Either.right(paymentMethod);
     }
 
     @Override
-    public Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId) {
+    public Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId) {
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, PaymentMethodInfo> getPaymentMethodInfo(String paymentMethodId) {
+    public Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethodInfo(String paymentMethodId) {
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, List<PaymentMethodInfo>> getPaymentMethods(final String accountKey) {
+    public Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(final String accountKey) {
         return Either.right(Arrays.<PaymentMethodInfo>asList());
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentGateway(String accountKey) {
+    public Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey) {
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentProviderAccountExistingContact(Account account) {
+    public Either<PaymentErrorEvent, Void> updatePaymentProviderAccountExistingContact(Account account) {
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentProviderAccountWithNewContact(Account account) {
+    public Either<PaymentErrorEvent, Void> updatePaymentProviderAccountWithNewContact(Account account) {
         return Either.right(null);
     }
 
     @Override
-    public List<Either<PaymentError, PaymentInfo>> processRefund(Account account) {
+    public List<Either<PaymentErrorEvent, PaymentInfoEvent>> processRefund(Account account) {
         // TODO Auto-generated method stub
         return null;
     }
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPlugin.java
index fd9d160..2daa160 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPlugin.java
@@ -21,27 +21,27 @@ import java.util.List;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.payment.api.Either;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentMethodInfo;
 import com.ning.billing.payment.api.PaymentProviderAccount;
 
 public interface PaymentProviderPlugin {
-    Either<PaymentError, PaymentInfo> processInvoice(Account account, Invoice invoice);
-    Either<PaymentError, String> createPaymentProviderAccount(Account account);
+    Either<PaymentErrorEvent, PaymentInfoEvent> processInvoice(Account account, Invoice invoice);
+    Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account);
 
-    Either<PaymentError, PaymentInfo> getPaymentInfo(String paymentId);
-    Either<PaymentError, PaymentProviderAccount> getPaymentProviderAccount(String accountKey);
-    Either<PaymentError, Void> updatePaymentGateway(String accountKey);
+    Either<PaymentErrorEvent, PaymentInfoEvent> getPaymentInfo(String paymentId);
+    Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey);
+    Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey);
 
-    Either<PaymentError, PaymentMethodInfo> getPaymentMethodInfo(String paymentMethodId);
-    Either<PaymentError, List<PaymentMethodInfo>> getPaymentMethods(String accountKey);
-    Either<PaymentError, String> addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod);
-    Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo);
-    Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId);
+    Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethodInfo(String paymentMethodId);
+    Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey);
+    Either<PaymentErrorEvent, String> addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod);
+    Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo);
+    Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId);
 
-    Either<PaymentError, Void> updatePaymentProviderAccountExistingContact(Account account);
-    Either<PaymentError, Void> updatePaymentProviderAccountWithNewContact(Account account);
-    List<Either<PaymentError, PaymentInfo>> processRefund(Account account);
 
+    Either<PaymentErrorEvent, Void> updatePaymentProviderAccountExistingContact(Account account);
+    Either<PaymentErrorEvent, Void> updatePaymentProviderAccountWithNewContact(Account account);
+    List<Either<PaymentErrorEvent, PaymentInfoEvent>> processRefund(Account account);
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPluginRegistry.java b/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPluginRegistry.java
index fc9c149..bdad7c6 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPluginRegistry.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/PaymentProviderPluginRegistry.java
@@ -22,7 +22,8 @@ import java.util.concurrent.ConcurrentHashMap;
 import org.apache.commons.lang.StringUtils;
 
 import com.google.inject.Inject;
-import com.ning.billing.payment.setup.PaymentConfig;
+import com.ning.billing.config.PaymentConfig;
+
 
 public class PaymentProviderPluginRegistry {
     private final String defaultPlugin;
diff --git a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
index e8034a1..45afaa7 100644
--- a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
@@ -31,11 +31,11 @@ import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.invoice.api.InvoiceCreationNotification;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.payment.api.Either;
 import com.ning.billing.payment.api.PaymentApi;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
@@ -62,7 +62,7 @@ public class RequestProcessor {
     }
 
     @Subscribe
-    public void receiveInvoice(InvoiceCreationNotification event) {
+    public void receiveInvoice(InvoiceCreationEvent event) {
         log.info("Received invoice creation notification for account {} and invoice {}", event.getAccountId(), event.getInvoiceId());
         try {
             final Account account = accountUserApi.getAccountById(event.getAccountId());
@@ -72,9 +72,9 @@ public class RequestProcessor {
             }
             else {
                 CallContext context = new DefaultCallContext("PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, clock);
-                List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
+                List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
                 if (!results.isEmpty()) {
-                    Either<PaymentError, PaymentInfo> result = results.get(0);
+                    Either<PaymentErrorEvent, PaymentInfoEvent> result = results.get(0);
                     eventBus.post(result.isLeft() ? result.getLeft() : result.getRight());
                 }
             }
diff --git a/payment/src/main/java/com/ning/billing/payment/RetryService.java b/payment/src/main/java/com/ning/billing/payment/RetryService.java
index d03b241..7558fbe 100644
--- a/payment/src/main/java/com/ning/billing/payment/RetryService.java
+++ b/payment/src/main/java/com/ning/billing/payment/RetryService.java
@@ -26,14 +26,15 @@ import com.ning.billing.util.clock.Clock;
 import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
+import com.ning.billing.config.PaymentConfig;
 import com.ning.billing.lifecycle.KillbillService;
 import com.ning.billing.lifecycle.LifecycleHandlerType;
 import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentStatus;
-import com.ning.billing.payment.setup.PaymentConfig;
+
 import com.ning.billing.util.notificationq.NotificationKey;
 import com.ning.billing.util.notificationq.NotificationQueue;
 import com.ning.billing.util.notificationq.NotificationQueueService;
@@ -103,7 +104,7 @@ public class RetryService implements KillbillService {
     }
 
     private void retry(String paymentAttemptId, CallContext context) {
-        PaymentInfo paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
+        PaymentInfoEvent paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
 
         if (paymentInfo != null && PaymentStatus.Processed.equals(PaymentStatus.valueOf(paymentInfo.getStatus()))) {
             // update payment attempt with success and notify invoice api of payment
diff --git a/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java b/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
index 0c769fd..de4bf3c 100644
--- a/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
+++ b/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
@@ -21,6 +21,7 @@ import java.util.Properties;
 import org.skife.config.ConfigurationObjectFactory;
 
 import com.google.inject.AbstractModule;
+import com.ning.billing.config.PaymentConfig;
 import com.ning.billing.payment.RequestProcessor;
 import com.ning.billing.payment.RetryService;
 import com.ning.billing.payment.api.DefaultPaymentApi;
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 9d89bdf..c5ca20c 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -95,12 +95,12 @@ public abstract class TestPaymentApi {
                                                        new BigDecimal("1.0"),
                                                        Currency.USD));
 
-        List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
+        List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
 
         assertEquals(results.size(), 1);
         assertTrue(results.get(0).isRight());
 
-        PaymentInfo paymentInfo = results.get(0).getRight();
+        PaymentInfoEvent paymentInfo = results.get(0).getRight();
 
         assertNotNull(paymentInfo.getPaymentId());
         assertTrue(paymentInfo.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
@@ -118,11 +118,11 @@ public abstract class TestPaymentApi {
         DateTime paymentAttemptDateTruncated = paymentAttempt.getPaymentAttemptDate().withMillisOfSecond(0).withSecondOfMinute(0);
         assertEquals(paymentAttemptDateTruncated.compareTo(nowTruncated), 0);
 
-        List<PaymentInfo> paymentInfos = paymentApi.getPaymentInfo(Arrays.asList(invoice.getId().toString()));
+        List<PaymentInfoEvent> paymentInfos = paymentApi.getPaymentInfo(Arrays.asList(invoice.getId().toString()));
         assertNotNull(paymentInfos);
         assertTrue(paymentInfos.size() > 0);
 
-        PaymentInfo paymentInfoFromGet = paymentInfos.get(0);
+        PaymentInfoEvent paymentInfoFromGet = paymentInfos.get(0);
         assertEquals(paymentInfo.getAmount(), paymentInfoFromGet.getAmount());
         assertEquals(paymentInfo.getRefundAmount(), paymentInfoFromGet.getRefundAmount());
         assertEquals(paymentInfo.getPaymentId(), paymentInfoFromGet.getPaymentId());
@@ -149,17 +149,17 @@ public abstract class TestPaymentApi {
                                                                            .setEmail(account.getEmail())
                                                                            .setDefaultMethod(true)
                                                                            .build();
-        Either<PaymentError, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
+        Either<PaymentErrorEvent, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
 
         assertTrue(paymentMethodIdOrError.isRight());
         assertNotNull(paymentMethodIdOrError.getRight());
 
-        Either<PaymentError, PaymentMethodInfo> paymentMethodInfoOrError = paymentApi.getPaymentMethod(accountKey, paymentMethodIdOrError.getRight());
+        Either<PaymentErrorEvent, PaymentMethodInfo> paymentMethodInfoOrError = paymentApi.getPaymentMethod(accountKey, paymentMethodIdOrError.getRight());
 
         assertTrue(paymentMethodInfoOrError.isRight());
         assertNotNull(paymentMethodInfoOrError.getRight());
 
-        Either<PaymentError, PaymentProviderAccount> accountOrError = paymentApi.getPaymentProviderAccount(accountKey);
+        Either<PaymentErrorEvent, PaymentProviderAccount> accountOrError = paymentApi.getPaymentProviderAccount(accountKey);
 
         assertTrue(accountOrError.isRight());
 
@@ -170,7 +170,7 @@ public abstract class TestPaymentApi {
     public void testCreatePaypalPaymentMethod() throws AccountApiException, EntityPersistenceException {
         PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
         assertNotNull(account);
-        Either<PaymentError, List<PaymentMethodInfo>> paymentMethodsOrError = paymentApi.getPaymentMethods(account.getAccountKey());
+        Either<PaymentErrorEvent, List<PaymentMethodInfo>> paymentMethodsOrError = paymentApi.getPaymentMethods(account.getAccountKey());
     }
 
     @Test(enabled=true)
@@ -191,7 +191,7 @@ public abstract class TestPaymentApi {
                                                                   .billingCycleDay(account.getBillCycleDay())
                                                                   .build();
 
-        Either<PaymentError, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
+        Either<PaymentErrorEvent, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
         assertTrue(voidOrError.isRight());
     }
 
@@ -199,7 +199,7 @@ public abstract class TestPaymentApi {
     public void testCannotDeleteDefaultPaymentMethod() throws AccountApiException, EntityPersistenceException {
         PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
 
-        Either<PaymentError, Void> errorOrVoid = paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
+        Either<PaymentErrorEvent, Void> errorOrVoid = paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
 
         assertTrue(errorOrVoid.isLeft());
     }
@@ -212,24 +212,24 @@ public abstract class TestPaymentApi {
         String accountKey = account.getExternalKey();
 
         PaypalPaymentMethodInfo paymentMethod1 = new PaypalPaymentMethodInfo.Builder().setDefaultMethod(false).setBaid("12345").setEmail(account.getEmail()).build();
-        Either<PaymentError, String> paymentMethodIdOrError1 = paymentApi.addPaymentMethod(accountKey, paymentMethod1, context);
+        Either<PaymentErrorEvent, String> paymentMethodIdOrError1 = paymentApi.addPaymentMethod(accountKey, paymentMethod1, context);
 
         assertTrue(paymentMethodIdOrError1.isRight());
         assertNotNull(paymentMethodIdOrError1.getRight());
 
         PaypalPaymentMethodInfo paymentMethod2 = new PaypalPaymentMethodInfo.Builder().setDefaultMethod(true).setBaid("12345").setEmail(account.getEmail()).build();
 
-        Either<PaymentError, String> paymentMethodIdOrError2 = paymentApi.addPaymentMethod(accountKey, paymentMethod2, context);
+        Either<PaymentErrorEvent, String> paymentMethodIdOrError2 = paymentApi.addPaymentMethod(accountKey, paymentMethod2, context);
 
         assertTrue(paymentMethodIdOrError2.isRight());
         assertNotNull(paymentMethodIdOrError2.getRight());
 
-        Either<PaymentError, List<PaymentMethodInfo>> paymentMethodsOrError = paymentApi.getPaymentMethods(accountKey);
+        Either<PaymentErrorEvent, List<PaymentMethodInfo>> paymentMethodsOrError = paymentApi.getPaymentMethods(accountKey);
 
         assertTrue(paymentMethodsOrError.isRight());
 
-        Either<PaymentError, Void> errorOrVoid1 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError1.getRight(), context);
-        Either<PaymentError, Void> errorOrVoid2 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError2.getRight(), context);
+        Either<PaymentErrorEvent, Void> errorOrVoid1 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError1.getRight(), context);
+        Either<PaymentErrorEvent, Void> errorOrVoid2 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError2.getRight(), context);
 
         assertTrue(errorOrVoid1.isRight());
         assertTrue(errorOrVoid2.isLeft());
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
index 7c8239f..a0a77ad 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
@@ -29,11 +29,12 @@ import org.apache.commons.collections.CollectionUtils;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.payment.api.DefaultPaymentInfo;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 
 public class MockPaymentDao implements PaymentDao {
-    private final Map<String, PaymentInfo> payments = new ConcurrentHashMap<String, PaymentInfo>();
+    private final Map<String, PaymentInfoEvent> payments = new ConcurrentHashMap<String, PaymentInfoEvent>();
     private final Map<UUID, PaymentAttempt> paymentAttempts = new ConcurrentHashMap<UUID, PaymentAttempt>();
 
     @Override
@@ -70,7 +71,7 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void savePaymentInfo(PaymentInfo paymentInfo, CallContext context) {
+    public void savePaymentInfo(PaymentInfoEvent paymentInfo, CallContext context) {
         payments.put(paymentInfo.getPaymentId(), paymentInfo);
     }
 
@@ -97,9 +98,9 @@ public class MockPaymentDao implements PaymentDao {
 
     @Override
     public void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry, CallContext context) {
-        PaymentInfo existingPayment = payments.get(paymentId);
+        DefaultPaymentInfo existingPayment = (DefaultPaymentInfo) payments.get(paymentId);
         if (existingPayment != null) {
-            PaymentInfo payment = existingPayment.cloner()
+            PaymentInfoEvent payment = existingPayment.cloner()
                     .setPaymentMethod(paymentMethodType)
                     .setCardType(cardType)
                     .setCardCountry(cardCountry)
@@ -110,14 +111,14 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public List<PaymentInfo> getPaymentInfo(List<String> invoiceIds) {
+    public List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds) {
         List<PaymentAttempt> attempts = getPaymentAttemptsForInvoiceIds(invoiceIds);
-        List<PaymentInfo> paymentsToReturn = new ArrayList<PaymentInfo>(invoiceIds.size());
+        List<PaymentInfoEvent> paymentsToReturn = new ArrayList<PaymentInfoEvent>(invoiceIds.size());
 
         for (final PaymentAttempt attempt : attempts) {
-            paymentsToReturn.addAll(Collections2.filter(payments.values(), new Predicate<PaymentInfo>() {
+            paymentsToReturn.addAll(Collections2.filter(payments.values(), new Predicate<PaymentInfoEvent>() {
                 @Override
-                public boolean apply(PaymentInfo input) {
+                public boolean apply(PaymentInfoEvent input) {
                     return input.getPaymentId().equals(attempt.getPaymentId());
                 }
             }));
@@ -143,7 +144,7 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public PaymentInfo getPaymentInfoForPaymentAttemptId(String paymentAttemptId) {
+    public PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptId) {
         // TODO Auto-generated method stub
         return null;
     }
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index 472fc2f..6bbc037 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -34,8 +34,9 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.api.DefaultPaymentInfo;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 
 public abstract class TestPaymentDao {
     protected PaymentDao paymentDao;
@@ -43,7 +44,7 @@ public abstract class TestPaymentDao {
 
     @Test
     public void testCreatePayment() {
-        PaymentInfo paymentInfo = new PaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
+        PaymentInfoEvent paymentInfo = new DefaultPaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
                 .setAmount(BigDecimal.TEN)
                 .setStatus("Processed")
                 .setBankIdentificationNumber("1234")
@@ -59,7 +60,7 @@ public abstract class TestPaymentDao {
 
     @Test
     public void testUpdatePaymentInfo() {
-        PaymentInfo paymentInfo = new PaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
+        PaymentInfoEvent paymentInfo = new DefaultPaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
                 .setAmount(BigDecimal.TEN)
                 .setStatus("Processed")
                 .setBankIdentificationNumber("1234")
@@ -118,7 +119,7 @@ public abstract class TestPaymentDao {
 
         Assert.assertEquals(attempt3, attempt4);
 
-        PaymentInfo originalPaymentInfo = new PaymentInfo.Builder().setPaymentId(paymentId)
+        PaymentInfoEvent originalPaymentInfo = new DefaultPaymentInfo.Builder().setPaymentId(paymentId)
                 .setAmount(invoiceAmount)
                 .setStatus("Processed")
                 .setBankIdentificationNumber("1234")
@@ -132,7 +133,7 @@ public abstract class TestPaymentDao {
                 .build();
 
         paymentDao.savePaymentInfo(originalPaymentInfo, thisContext);
-        PaymentInfo paymentInfo = paymentDao.getPaymentInfo(Arrays.asList(invoiceId.toString())).get(0);
+        PaymentInfoEvent paymentInfo = paymentDao.getPaymentInfo(Arrays.asList(invoiceId.toString())).get(0);
         Assert.assertEquals(paymentInfo, originalPaymentInfo);
 
         clock.setDeltaFromReality(60 * 60 * 1000); // move clock forward one hour
diff --git a/payment/src/test/java/com/ning/billing/payment/MockPaymentInfoReceiver.java b/payment/src/test/java/com/ning/billing/payment/MockPaymentInfoReceiver.java
index cf2494d..f4a30a9 100644
--- a/payment/src/test/java/com/ning/billing/payment/MockPaymentInfoReceiver.java
+++ b/payment/src/test/java/com/ning/billing/payment/MockPaymentInfoReceiver.java
@@ -21,29 +21,29 @@ import java.util.Collections;
 import java.util.List;
 
 import com.google.common.eventbus.Subscribe;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 
 public class MockPaymentInfoReceiver {
-    private final List<PaymentInfo> processedPayments = Collections.synchronizedList(new ArrayList<PaymentInfo>());
-    private final List<PaymentError> errors = Collections.synchronizedList(new ArrayList<PaymentError>());
+    private final List<PaymentInfoEvent> processedPayments = Collections.synchronizedList(new ArrayList<PaymentInfoEvent>());
+    private final List<PaymentErrorEvent> errors = Collections.synchronizedList(new ArrayList<PaymentErrorEvent>());
 
     @Subscribe
-    public void processedPayment(PaymentInfo paymentInfo) {
+    public void processedPayment(PaymentInfoEvent paymentInfo) {
         processedPayments.add(paymentInfo);
     }
 
     @Subscribe
-    public void processedPaymentError(PaymentError paymentError) {
+    public void processedPaymentError(PaymentErrorEvent paymentError) {
         errors.add(paymentError);
     }
 
-    public List<PaymentInfo> getProcessedPayments() {
-        return new ArrayList<PaymentInfo>(processedPayments);
+    public List<PaymentInfoEvent> getProcessedPayments() {
+        return new ArrayList<PaymentInfoEvent>(processedPayments);
     }
 
-    public List<PaymentError> getErrors() {
-        return new ArrayList<PaymentError>(errors);
+    public List<PaymentErrorEvent> getErrors() {
+        return new ArrayList<PaymentErrorEvent>(errors);
     }
 
     public void clear() {
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 adda477..c027985 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
@@ -32,9 +32,11 @@ import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.payment.api.CreditCardPaymentMethodInfo;
+import com.ning.billing.payment.api.DefaultPaymentError;
+import com.ning.billing.payment.api.DefaultPaymentInfo;
 import com.ning.billing.payment.api.Either;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentMethodInfo;
 import com.ning.billing.payment.api.PaymentProviderAccount;
 import com.ning.billing.payment.api.PaypalPaymentMethodInfo;
@@ -42,7 +44,7 @@ import com.ning.billing.util.clock.Clock;
 
 public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     private final AtomicBoolean makeNextInvoiceFail = new AtomicBoolean(false);
-    private final Map<String, PaymentInfo> payments = new ConcurrentHashMap<String, PaymentInfo>();
+    private final Map<String, PaymentInfoEvent> payments = new ConcurrentHashMap<String, PaymentInfoEvent>();
     private final Map<String, PaymentProviderAccount> accounts = new ConcurrentHashMap<String, PaymentProviderAccount>();
     private final Map<String, PaymentMethodInfo> paymentMethods = new ConcurrentHashMap<String, PaymentMethodInfo>();
     private final Clock clock;
@@ -57,12 +59,12 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public Either<PaymentError, PaymentInfo> processInvoice(Account account, Invoice invoice) {
+    public Either<PaymentErrorEvent, PaymentInfoEvent> processInvoice(Account account, Invoice invoice) {
         if (makeNextInvoiceFail.getAndSet(false)) {
-            return Either.left(new PaymentError("unknown", "test error", account.getId(), invoice.getId()));
+            return Either.left((PaymentErrorEvent) new DefaultPaymentError("unknown", "test error", account.getId(), invoice.getId(), null));
         }
         else {
-            PaymentInfo payment = new PaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
+            PaymentInfoEvent payment = new DefaultPaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
                                                  .setAmount(invoice.getBalance())
                                                  .setStatus("Processed")
                                                  .setBankIdentificationNumber("1234")
@@ -78,11 +80,11 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public Either<PaymentError, PaymentInfo> getPaymentInfo(String paymentId) {
-        PaymentInfo payment = payments.get(paymentId);
+    public Either<PaymentErrorEvent, PaymentInfoEvent> getPaymentInfo(String paymentId) {
+        PaymentInfoEvent payment = payments.get(paymentId);
 
         if (payment == null) {
-            return Either.left(new PaymentError("notfound", "No payment found for id " + paymentId, null, null));
+            return Either.left((PaymentErrorEvent) new DefaultPaymentError("notfound", "No payment found for id " + paymentId, null, null, null));
         }
         else {
             return Either.right(payment);
@@ -90,7 +92,7 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public Either<PaymentError, String> createPaymentProviderAccount(Account account) {
+    public Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account) {
         if (account != null) {
             String id = String.valueOf(RandomStringUtils.randomAlphanumeric(10));
             accounts.put(account.getExternalKey(),
@@ -101,22 +103,22 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
             return Either.right(id);
         }
         else {
-            return Either.left(new PaymentError("unknown", "Did not get account to create payment provider account", null, null));
+            return Either.left((PaymentErrorEvent)  new DefaultPaymentError("unknown", "Did not get account to create payment provider account", null, null, null));
         }
     }
 
     @Override
-    public Either<PaymentError, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
+    public Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
         if (accountKey != null) {
             return Either.right(accounts.get(accountKey));
         }
         else {
-            return Either.left(new PaymentError("unknown", "Did not get account for accountKey " + accountKey, null, null));
+            return Either.left((PaymentErrorEvent) new DefaultPaymentError("unknown", "Did not get account for accountKey " + accountKey, null, null, null));
         }
     }
 
     @Override
-    public Either<PaymentError, String> addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
+    public Either<PaymentErrorEvent, String> addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
         if (paymentMethod != null) {
             PaymentProviderAccount account = accounts.get(accountKey);
 
@@ -143,7 +145,7 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
                     realPaymentMethod = new CreditCardPaymentMethodInfo.Builder(ccPaymentMethod).setId(paymentMethodId).build();
                 }
                 if (realPaymentMethod == null) {
-                    return Either.left(new PaymentError("unsupported", "Payment method " + paymentMethod.getType() + " not supported by the plugin", null, null));
+                    return Either.left((PaymentErrorEvent)  new DefaultPaymentError("unsupported", "Payment method " + paymentMethod.getType() + " not supported by the plugin", null, null, null));
                 }
                 else {
                     if (shouldBeDefault) {
@@ -154,11 +156,11 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
                 }
             }
                 else {
-                    return Either.left(new PaymentError("noaccount", "Could not retrieve account for accountKey " + accountKey, null, null));
+                    return Either.left((PaymentErrorEvent)  new DefaultPaymentError("noaccount", "Could not retrieve account for accountKey " + accountKey, null, null, null));
                 }
         }
         else {
-            return Either.left(new PaymentError("unknown", "Could not create add payment method " + paymentMethod + " for " + accountKey, null, null));
+            return Either.left((PaymentErrorEvent)  new DefaultPaymentError("unknown", "Could not create add payment method " + paymentMethod + " for " + accountKey, null, null, null));
         }
     }
 
@@ -189,7 +191,7 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
+    public Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethod) {
         if (paymentMethod != null) {
             PaymentMethodInfo realPaymentMethod = null;
 
@@ -202,7 +204,7 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
                 realPaymentMethod = new CreditCardPaymentMethodInfo.Builder(ccPaymentMethod).build();
             }
             if (realPaymentMethod == null) {
-                return Either.left(new PaymentError("unsupported", "Payment method " + paymentMethod.getType() + " not supported by the plugin", null, null));
+                return Either.left((PaymentErrorEvent)  new DefaultPaymentError("unsupported", "Payment method " + paymentMethod.getType() + " not supported by the plugin", null, null, null));
             }
             else {
                 paymentMethods.put(paymentMethod.getId(), paymentMethod);
@@ -210,37 +212,37 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
             }
         }
         else {
-            return Either.left(new PaymentError("unknown", "Could not create add payment method " + paymentMethod + " for " + accountKey, null, null));
+            return Either.left((PaymentErrorEvent)  new DefaultPaymentError("unknown", "Could not create add payment method " + paymentMethod + " for " + accountKey, null, null, null));
         }
     }
 
     @Override
-    public Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId) {
+    public Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId) {
         PaymentMethodInfo paymentMethodInfo = paymentMethods.get(paymentMethodId);
         if (paymentMethodInfo != null) {
             if (Boolean.FALSE.equals(paymentMethodInfo.getDefaultMethod()) || paymentMethodInfo.getDefaultMethod() == null) {
                 if (paymentMethods.remove(paymentMethodId) == null) {
-                    return Either.left(new PaymentError("unknown", "Did not get any result back", null, null));
+                    return Either.left((PaymentErrorEvent) new DefaultPaymentError("unknown", "Did not get any result back", null, null, null));
                 }
             }
             else {
-                return Either.left(new PaymentError("error", "Cannot delete default payment method", null, null));
+                return Either.left((PaymentErrorEvent) new DefaultPaymentError("error", "Cannot delete default payment method", null, null, null));
             }
         }
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, PaymentMethodInfo> getPaymentMethodInfo(String paymentMethodId) {
+    public Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethodInfo(String paymentMethodId) {
         if (paymentMethodId == null) {
-            return Either.left(new PaymentError("unknown", "Could not retrieve payment method for paymentMethodId " + paymentMethodId, null, null));
+            return Either.left((PaymentErrorEvent) new DefaultPaymentError("unknown", "Could not retrieve payment method for paymentMethodId " + paymentMethodId, null, null, null));
         }
 
         return Either.right(paymentMethods.get(paymentMethodId));
     }
 
     @Override
-    public Either<PaymentError, List<PaymentMethodInfo>> getPaymentMethods(final String accountKey) {
+    public Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(final String accountKey) {
 
         Collection<PaymentMethodInfo> filteredPaymentMethods = Collections2.filter(paymentMethods.values(), new Predicate<PaymentMethodInfo>() {
             @Override
@@ -253,26 +255,23 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentGateway(String accountKey) {
+    public Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey) {
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentProviderAccountExistingContact(Account account) {
+    public Either<PaymentErrorEvent, Void> updatePaymentProviderAccountExistingContact(Account account) {
         // nothing to do here
         return Either.right(null);
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentProviderAccountWithNewContact(Account account) {
-        // TODO Auto-generated method stub
-        return null;
+    public Either<PaymentErrorEvent, Void> updatePaymentProviderAccountWithNewContact(Account account) {
+        return Either.right(null);
     }
 
     @Override
-    public List<Either<PaymentError, PaymentInfo>> processRefund(Account account) {
-        // TODO Auto-generated method stub
+    public List<Either<PaymentErrorEvent, PaymentInfoEvent>> processRefund(Account account) {
         return null;
     }
-
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithEmbeddedDb.java b/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithEmbeddedDb.java
index 97aa31e..8faf1f3 100644
--- a/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithEmbeddedDb.java
+++ b/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithEmbeddedDb.java
@@ -20,6 +20,7 @@ import org.apache.commons.collections.MapUtils;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.inject.Provider;
+import com.ning.billing.config.PaymentConfig;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
diff --git a/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithMocks.java b/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithMocks.java
index c8f79bc..b0999da 100644
--- a/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithMocks.java
+++ b/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithMocks.java
@@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.inject.Provider;
 import com.ning.billing.account.dao.AccountDao;
 import com.ning.billing.account.dao.MockAccountDao;
+import com.ning.billing.config.PaymentConfig;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.invoice.dao.InvoiceDao;
 import com.ning.billing.invoice.dao.MockInvoiceDao;
diff --git a/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java b/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
index 8b71c10..d30ec44 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
@@ -50,8 +50,8 @@ import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.invoice.glue.InvoiceModuleWithMocks;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.setup.PaymentTestModuleWithEmbeddedDb;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
@@ -137,8 +137,8 @@ public class TestPaymentInvoiceIntegration {
         await().atMost(1, MINUTES).until(new Callable<Boolean>() {
             @Override
             public Boolean call() throws Exception {
-                List<PaymentInfo> processedPayments = paymentInfoReceiver.getProcessedPayments();
-                List<PaymentError> errors = paymentInfoReceiver.getErrors();
+                List<PaymentInfoEvent> processedPayments = paymentInfoReceiver.getProcessedPayments();
+                List<PaymentErrorEvent> errors = paymentInfoReceiver.getErrors();
 
                 return processedPayments.size() == 1 || errors.size() == 1;
             }
@@ -147,7 +147,7 @@ public class TestPaymentInvoiceIntegration {
         assertFalse(paymentInfoReceiver.getProcessedPayments().isEmpty());
         assertTrue(paymentInfoReceiver.getErrors().isEmpty());
 
-        List<PaymentInfo> payments = paymentInfoReceiver.getProcessedPayments();
+        List<PaymentInfoEvent> payments = paymentInfoReceiver.getProcessedPayments();
         PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(payments.get(0).getPaymentId());
         Assert.assertNotNull(paymentAttempt);
 
diff --git a/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java b/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java
index dd4b996..983fc3b 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestPaymentProvider.java
@@ -34,8 +34,8 @@ import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.glue.AccountModuleWithMocks;
 import com.ning.billing.invoice.glue.InvoiceModuleWithMocks;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.setup.PaymentTestModuleWithMocks;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
@@ -80,8 +80,8 @@ public class TestPaymentProvider {
         await().atMost(1, MINUTES).until(new Callable<Boolean>() {
             @Override
             public Boolean call() throws Exception {
-                List<PaymentInfo> processedPayments = paymentInfoReceiver.getProcessedPayments();
-                List<PaymentError> errors = paymentInfoReceiver.getErrors();
+                List<PaymentInfoEvent> processedPayments = paymentInfoReceiver.getProcessedPayments();
+                List<PaymentErrorEvent> errors = paymentInfoReceiver.getErrors();
 
                 return processedPayments.size() == 1 || errors.size() == 1;
             }
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 16d21e6..26414aa 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -41,19 +41,19 @@ import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.glue.AccountModuleWithMocks;
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.config.PaymentConfig;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.glue.InvoiceModuleWithMocks;
 import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.payment.api.Either;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentError;
-import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
-import com.ning.billing.payment.setup.PaymentConfig;
 import com.ning.billing.payment.setup.PaymentTestModuleWithMocks;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.clock.Clock;
@@ -133,7 +133,7 @@ public class TestRetryService {
 
         mockPaymentProviderPlugin.makeNextInvoiceFail();
 
-        List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
+        List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
 
         assertEquals(results.size(), 1);
         assertTrue(results.get(0).isLeft());
@@ -189,10 +189,10 @@ public class TestRetryService {
         List<Notification> pendingNotifications = mockNotificationQueue.getPendingEvents();
         assertEquals(pendingNotifications.size(), 0);
 
-        List<PaymentInfo> paymentInfoList = paymentApi.getPaymentInfo(Arrays.asList(invoice.getId().toString()));
+        List<PaymentInfoEvent> paymentInfoList = paymentApi.getPaymentInfo(Arrays.asList(invoice.getId().toString()));
         assertEquals(paymentInfoList.size(), 1);
 
-        PaymentInfo paymentInfo = paymentInfoList.get(0);
+        PaymentInfoEvent paymentInfo = paymentInfoList.get(0);
         assertEquals(paymentInfo.getStatus(), PaymentStatus.Processed.toString());
 
         List<PaymentAttempt> updatedAttempts = paymentApi.getPaymentAttemptsForInvoiceId(invoice.getId().toString());

pom.xml 69(+58 -11)

diff --git a/pom.xml b/pom.xml
index 8252d49..f7ab718 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,12 +44,42 @@
         <module>catalog</module>
         <module>entitlement</module>
         <module>invoice</module>
-        <module>payment</module>
+        <module>ne</module>
         <module>overdue</module>
+        <module>payment</module>
         <module>util</module>
+        <module>jaxrs</module>
+        <module>server</module>
     </modules>
     <dependencyManagement>
         <dependencies>
+           <dependency>
+                <groupId>javax.ws.rs</groupId>
+                <artifactId>jsr311-api</artifactId>
+                <version>1.1.1</version>
+           </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-beatrix</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-beatrix</artifactId>
+                <version>${project.version}</version>
+                <type>test-jar</type>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-analytics</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-jaxrs</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>com.ning.billing</groupId>
                 <artifactId>killbill-api</artifactId>
@@ -64,6 +94,11 @@
             </dependency>
             <dependency>
                 <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
                 <artifactId>killbill-account</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -76,6 +111,18 @@
             </dependency>
             <dependency>
                 <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-ne</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-ne</artifactId>
+                <version>${project.version}</version>
+                <type>test-jar</type>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
                 <artifactId>killbill-entitlement</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -137,17 +184,17 @@
             <dependency>
                 <groupId>org.codehaus.jackson</groupId>
                 <artifactId>jackson-core-asl</artifactId>
-                <version>1.9.2</version>
+                <version>1.9.5</version>
             </dependency>
             <dependency>
                 <groupId>org.codehaus.jackson</groupId>
                 <artifactId>jackson-jaxrs</artifactId>
-                <version>1.9.2</version>
+                <version>1.9.5</version>
             </dependency>
             <dependency>
                 <groupId>org.codehaus.jackson</groupId>
                 <artifactId>jackson-mapper-asl</artifactId>
-                <version>1.9.2</version>
+                <version>1.9.5</version>
             </dependency>
             <dependency>
                 <groupId>com.jolbox</groupId>
@@ -203,7 +250,7 @@
             <dependency>
                 <groupId>commons-lang</groupId>
                 <artifactId>commons-lang</artifactId>
-                <version>2.5</version>
+                <version>2.6</version>
             </dependency>
             <dependency>
                 <groupId>commons-collections</groupId>
@@ -236,32 +283,32 @@
             <dependency>
                 <groupId>org.jdbi</groupId>
                 <artifactId>jdbi</artifactId>
-                <version>2.31.2</version>
+                <version>2.32</version>
             </dependency>
             <dependency>
                 <groupId>org.skife.config</groupId>
                 <artifactId>config-magic</artifactId>
-                <version>0.9</version>
+                <version>0.13</version>
             </dependency>
             <dependency>
                 <groupId>org.slf4j</groupId>
                 <artifactId>slf4j-api</artifactId>
-                <version>1.6.3</version>
+                <version>1.6.4</version>
             </dependency>
             <dependency>
                 <groupId>org.slf4j</groupId>
                 <artifactId>jcl-over-slf4j</artifactId>
-                <version>1.6.3</version>
+                <version>1.6.4</version>
             </dependency>
             <dependency>
                 <groupId>org.slf4j</groupId>
                 <artifactId>jul-to-slf4j</artifactId>
-                <version>1.6.3</version>
+                <version>1.6.4</version>
             </dependency>
             <dependency>
                 <groupId>org.slf4j</groupId>
                 <artifactId>slf4j-log4j12</artifactId>
-                <version>1.6.3</version>
+                <version>1.6.4</version>
             </dependency>
             <dependency>
                 <groupId>org.testng</groupId>

server/pom.xml 426(+426 -0)

diff --git a/server/pom.xml b/server/pom.xml
new file mode 100644
index 0000000..ea39345
--- /dev/null
+++ b/server/pom.xml
@@ -0,0 +1,426 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 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</artifactId>
+		<version>0.1.11-SNAPSHOT</version>
+		<relativePath>../pom.xml</relativePath>
+	</parent>
+	<artifactId>killbill-server</artifactId>
+	<name>killbill-server</name>
+	<packaging>war</packaging>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<guice.version>3.0</guice.version>
+		<jersey.version>1.12</jersey.version>
+		<jetty.version>8.1.2.v20120308</jetty.version>
+		<logback.version>1.0.1</logback.version>
+		<metrics.version>2.1.2</metrics.version>
+		<slf4j.version>1.6.4</slf4j.version>
+		<skeleton.version>0.1.2</skeleton.version>
+		<async-http-client.version>1.6.5</async-http-client.version>
+	</properties>
+
+	<dependencies>
+
+
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-http</artifactId>
+			<version>${jetty.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-io</artifactId>
+			<version>${jetty.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-util</artifactId>
+			<version>${jetty.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-server</artifactId>
+			<version>${jetty.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-deploy</artifactId>
+			<version>${jetty.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-jmx</artifactId>
+			<version>${jetty.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-xml</artifactId>
+			<version>${jetty.version}</version>
+			<scope>test</scope>
+		</dependency>
+
+
+
+		<!-- NOT in master POM; include version as well -->
+		<dependency>
+			<groupId>org.weakref</groupId>
+			<artifactId>jmxutils</artifactId>
+			<version>1.12</version>
+		</dependency>
+		<dependency>
+			<groupId>com.google.inject.extensions</groupId>
+			<artifactId>guice-servlet</artifactId>
+			<version>${guice.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.yammer.metrics</groupId>
+			<artifactId>metrics-core</artifactId>
+			<version>${metrics.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.yammer.metrics</groupId>
+			<artifactId>metrics-guice</artifactId>
+			<version>${metrics.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.sun.jersey</groupId>
+			<artifactId>jersey-server</artifactId>
+			<version>${jersey.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.sun.jersey.contribs</groupId>
+			<artifactId>jersey-guice</artifactId>
+			<version>${jersey.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>javax.servlet-api</artifactId>
+			<version>3.0.1</version>
+		</dependency>
+		<!-- Do we want to depend on skeleton -->
+		<dependency>
+			<groupId>com.ning.jetty</groupId>
+			<artifactId>ning-service-skeleton-base</artifactId>
+			<version>${skeleton.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.jetty</groupId>
+			<artifactId>ning-service-skeleton-jdbi</artifactId>
+			<version>${skeleton.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.jetty</groupId>
+			<artifactId>ning-service-skeleton-log4j</artifactId>
+			<version>${skeleton.version}</version>
+			<classifier>selfcontained</classifier>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+			<version>${slf4j.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>jcl-over-slf4j</artifactId>
+			<version>${slf4j.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>ch.qos.logback</groupId>
+			<artifactId>logback-core</artifactId>
+			<version>${logback.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>ch.qos.logback</groupId>
+			<artifactId>logback-classic</artifactId>
+			<version>${logback.version}</version>
+		</dependency>
+
+		<!-- FROM MASTER POM / LIBRARY -->
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-jaxrs</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-beatrix</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-util</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-entitlement</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-invoice</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-payment</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-catalog</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-analytics</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<version>11.0.2</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.google.inject</groupId>
+			<artifactId>guice</artifactId>
+			<scope>compile</scope>
+		</dependency>
+		<dependency><!-- Needed by jmxutils -->
+			<groupId>com.google.inject.extensions</groupId>
+			<artifactId>guice-multibindings</artifactId>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.antlr</groupId>
+			<artifactId>stringtemplate</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.skife.config</groupId>
+			<artifactId>config-magic</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>javax.ws.rs</groupId>
+			<artifactId>jsr311-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>joda-time</groupId>
+			<artifactId>joda-time</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning</groupId>
+			<artifactId>async-http-client</artifactId>
+			<version>${async-http-client.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.testng</groupId>
+			<artifactId>testng</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-util</artifactId>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-beatrix</artifactId>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-payment</artifactId>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-mxj</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-mxj-db-files</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+	<build>
+		<resources>
+			<resource>
+				<directory>${basedir}/src/main/resources</directory>
+			</resource>
+		</resources>
+		<plugins>
+			<plugin>
+				<groupId>com.ning.maven.plugins</groupId>
+				<artifactId>maven-dependency-versions-check-plugin</artifactId>
+				<version>2.0.2</version>
+				<configuration>
+					<failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>verify</phase>
+						<goals>
+							<goal>check</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<!-- To make eclipse happy -->
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-resources-plugin</artifactId>
+				<version>2.5</version>
+			</plugin>
+			<plugin>
+				<groupId>com.ning.maven.plugins</groupId>
+				<artifactId>maven-duplicate-finder-plugin</artifactId>
+				<version>1.0.2</version>
+				<configuration>
+					<failBuildInCaseOfConflict>false</failBuildInCaseOfConflict>
+					<!-- That's for Jetty -->
+					<ignoredResources>
+						<ignoredResource>about.html</ignoredResource>
+					</ignoredResources>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>verify</phase>
+						<goals>
+							<goal>check</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3.2</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<version>2.3</version>
+				<executions>
+					<execution>
+						<id>analyze</id>
+						<goals>
+							<goal>analyze-only</goal>
+						</goals>
+						<configuration>
+							<ignoreNonCompile>true</ignoreNonCompile>
+							<failOnWarning>false</failOnWarning>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-release-plugin</artifactId>
+				<version>2.2.1</version>
+				<configuration>
+					<mavenExecutorId>forked-path</mavenExecutorId>
+				</configuration>
+				<dependencies>
+					<dependency>
+						<groupId>org.apache.maven.scm</groupId>
+						<artifactId>maven-scm-provider-gitexe</artifactId>
+						<version>1.4</version>
+					</dependency>
+					<dependency>
+						<groupId>org.codehaus.plexus</groupId>
+						<artifactId>plexus-utils</artifactId>
+						<version>1.5.9</version>
+					</dependency>
+				</dependencies>
+			</plugin>
+			<plugin>
+				<!-- TODO: fix for http://jira.codehaus.org/browse/MSITE-286? -->
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-site-plugin</artifactId>
+				<version>3.0</version>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.1.1</version>
+				<configuration>
+					<attachClasses>true</attachClasses>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.mortbay.jetty</groupId>
+				<artifactId>jetty-maven-plugin</artifactId>
+				<version>${jetty.version}</version>
+				<dependencies>
+					<dependency><!-- For LogLevelCounterAppender -->
+						<groupId>com.ning.jetty</groupId>
+						<artifactId>ning-service-skeleton-log4j</artifactId>
+						<version>${skeleton.version}</version>
+						<classifier>selfcontained</classifier>
+						<scope>runtime</scope>
+					</dependency>
+					<!-- Needed to redirect Jetty logs to slf4j -->
+					<dependency>
+						<groupId>org.slf4j</groupId>
+						<artifactId>slf4j-api</artifactId>
+						<version>${slf4j.version}</version>
+					</dependency>
+					<dependency>
+						<groupId>ch.qos.logback</groupId>
+						<artifactId>logback-core</artifactId>
+						<version>${logback.version}</version>
+					</dependency>
+					<dependency>
+						<groupId>ch.qos.logback</groupId>
+						<artifactId>logback-classic</artifactId>
+						<version>${logback.version}</version>
+					</dependency>
+				</dependencies>
+				<configuration>
+					<scanIntervalSeconds>60</scanIntervalSeconds>
+					<systemProperties>
+						<systemProperty>
+							<name>logback.configurationFile</name>
+							<value>file:${basedir}/src/main/resources/logback.xml</value>
+						</systemProperty>
+					</systemProperties>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java b/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java
new file mode 100644
index 0000000..65e6faa
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010-2011 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.server.config;
+
+public interface KillbillServerConfig
+{
+	
+}
diff --git a/server/src/main/java/com/ning/billing/server/healthchecks/KillbillHealthcheck.java b/server/src/main/java/com/ning/billing/server/healthchecks/KillbillHealthcheck.java
new file mode 100644
index 0000000..62c79bf
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/healthchecks/KillbillHealthcheck.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010-2011 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.server.healthchecks;
+
+import com.yammer.metrics.core.HealthCheck;
+import org.weakref.jmx.Managed;
+
+public class KillbillHealthcheck extends HealthCheck
+{
+    public KillbillHealthcheck()
+    {
+        super(KillbillHealthcheck.class.getSimpleName());
+    }
+
+    @Override
+    public Result check()
+    {
+        try {
+            // STEPH obviously needs more than that
+            return Result.healthy();
+        }
+        catch (Exception e) {
+            return Result.unhealthy(e);
+        }
+    }
+
+    @Managed(description = "Basic killbill healthcheck")
+    public boolean isHealthy()
+    {
+        return check().isHealthy();
+    }
+}
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
new file mode 100644
index 0000000..11de6ec
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2010-2011 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.server.listeners;
+
+
+import com.ning.billing.beatrix.lifecycle.DefaultLifecycle;
+import com.ning.billing.jaxrs.util.KillbillEventHandler;
+import com.ning.billing.server.config.KillbillServerConfig;
+import com.ning.billing.server.healthchecks.KillbillHealthcheck;
+import com.ning.billing.server.modules.KillbillServerModule;
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.BusService;
+import com.ning.jetty.base.modules.ServerModuleBuilder;
+import com.ning.jetty.core.listeners.SetupServer;
+
+import com.google.inject.Injector;
+import com.google.inject.Module;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletContextEvent;
+
+public class KillbillGuiceListener extends SetupServer
+{
+    public static final Logger logger = LoggerFactory.getLogger(KillbillGuiceListener.class);
+
+    private DefaultLifecycle killbillLifecycle;
+    private BusService killbillBusService;
+    private KillbillEventHandler killbilleventHandler;
+
+    protected Injector theInjector;
+    
+    protected Module getModule() {
+    	return new KillbillServerModule();
+    }
+
+    @Override
+    public void contextInitialized(ServletContextEvent event)
+    {
+    	
+
+        final ServerModuleBuilder builder = new ServerModuleBuilder()
+                .addConfig(KillbillServerConfig.class)
+                .addHealthCheck(KillbillHealthcheck.class)
+                .addJMXExport(KillbillHealthcheck.class)
+                .addModule(getModule())
+                .addJerseyResource("com.ning.billing.jaxrs.resources");
+
+
+        guiceModule = builder.build();
+
+        super.contextInitialized(event);
+
+        logger.info("KillbillLifecycleListener : contextInitialized");
+        theInjector = injector(event);
+        killbillLifecycle = theInjector.getInstance(DefaultLifecycle.class);
+        killbillBusService = theInjector.getInstance(BusService.class);
+        killbilleventHandler = theInjector.getInstance(KillbillEventHandler.class); 
+
+        //
+        // Fire all Startup levels up to service start
+        //
+        killbillLifecycle.fireStartupSequencePriorEventRegistration();
+        //
+        // Perform Bus registration
+        //
+        try {
+            killbillBusService.getBus().register(killbilleventHandler);
+        }
+        catch (Bus.EventBusException e) {
+            logger.error("Failed to register for event notifications, this is bad exiting!", e);
+            System.exit(1);
+        }
+        // Let's start!
+        killbillLifecycle.fireStartupSequencePostEventRegistration();
+    }
+
+    @Override
+    public void contextDestroyed(ServletContextEvent sce)
+    {
+        super.contextDestroyed(sce);
+
+        logger.info("IrsKillbillListener : contextDestroyed");
+        // Stop services
+        // Guice error, no need to fill the screen with useless stack traces
+        if (killbillLifecycle == null) {
+            return;
+        }
+
+        killbillLifecycle.fireShutdownSequencePriorEventUnRegistration();
+
+        try {
+            killbillBusService.getBus().unregister(killbilleventHandler);
+        }
+        catch (Bus.EventBusException e) {
+            logger.warn("Failed to unregister for event notifications", e);
+        }
+
+        // Complete shutdown sequence
+        killbillLifecycle.fireShutdownSequencePostEventUnRegistration();
+    }
+}
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
new file mode 100644
index 0000000..2cdced0
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2010-2011 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.server.modules;
+
+import org.skife.jdbi.v2.DBI;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.account.glue.AccountModule;
+import com.ning.billing.analytics.setup.AnalyticsModule;
+import com.ning.billing.beatrix.glue.BeatrixModule;
+import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.jaxrs.resources.AccountResource;
+import com.ning.billing.jaxrs.resources.BundleResource;
+import com.ning.billing.jaxrs.resources.BundleTimelineResource;
+import com.ning.billing.jaxrs.resources.InvoiceResource;
+import com.ning.billing.jaxrs.resources.PaymentResource;
+import com.ning.billing.jaxrs.resources.SubscriptionResource;
+import com.ning.billing.jaxrs.util.KillbillEventHandler;
+import com.ning.billing.payment.setup.PaymentModule;
+import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.FieldStoreModule;
+import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.TagStoreModule;
+import com.ning.jetty.jdbi.guice.providers.DBIProvider;
+
+public class KillbillServerModule extends AbstractModule
+{
+    @Override
+    protected void configure() {
+        configureDao();
+        configureResources();
+        installKillbillModules();
+    }
+
+    protected void configureDao() {
+        bind(IDBI.class).to(DBI.class).asEagerSingleton();
+        bind(DBI.class).toProvider(DBIProvider.class).asEagerSingleton();
+    }
+
+    protected void configureResources() {
+        bind(AccountResource.class).asEagerSingleton();
+        bind(BundleResource.class).asEagerSingleton();
+        bind(SubscriptionResource.class).asEagerSingleton();
+        bind(BundleTimelineResource.class).asEagerSingleton();
+        bind(InvoiceResource.class).asEagerSingleton();
+        bind(PaymentResource.class).asEagerSingleton();
+        bind(KillbillEventHandler.class).asEagerSingleton();
+    }
+
+    protected void installClock() {
+        install(new ClockModule());    	
+    }
+    
+    protected void installKillbillModules() {
+        install(new FieldStoreModule());
+        install(new TagStoreModule());
+        install(new CatalogModule());
+    	install(new BusModule());
+        install(new NotificationQueueModule());
+        install(new CallContextModule());
+        install(new AccountModule());
+        install(new InvoiceModule());
+        install(new EntitlementModule());
+        install(new AnalyticsModule());
+        install(new PaymentModule());
+        install(new BeatrixModule());
+        installClock();
+    }
+}
diff --git a/server/src/main/jetty-config/contexts/root.xml b/server/src/main/jetty-config/contexts/root.xml
new file mode 100755
index 0000000..cdf71e1
--- /dev/null
+++ b/server/src/main/jetty-config/contexts/root.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"  encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Set name="contextPath">/</Set>
+    <Set name="war">
+        <SystemProperty name="xn.jetty.webapp.path" default="webapps/root"/>
+    </Set>
+    <Set name="defaultsDescriptor">
+        <SystemProperty name="xn.jetty.webapps.defaultsDescriptor" default="etc/webdefault.xml"/>
+    </Set>
+</Configure>
diff --git a/server/src/main/jetty-config/etc/webdefault.xml b/server/src/main/jetty-config/etc/webdefault.xml
new file mode 100755
index 0000000..19ae6ff
--- /dev/null
+++ b/server/src/main/jetty-config/etc/webdefault.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app
+        xmlns="http://java.sun.com/xml/ns/javaee"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+        metadata-complete="true"
+        version="2.5">
+    <description>
+        Default web.xml file.
+        This file is applied to a Web application before it's own WEB_INF/web.xml file
+    </description>
+    <context-param>
+        <param-name>org.mortbay.jetty.webapp.NoTLDJarPattern</param-name>
+        <param-value>
+            start.jar|ant-.*\.jar|dojo-.*\.jar|jetty-.*\.jar|jsp-api-.*\.jar|junit-.*\.jar|servlet-api-.*\.jar|dnsns\.jar|rt\.jar|jsse\.jar|tools\.jar|sunpkcs11\.jar|sunjce_provider\.jar|xerces.*\.jar
+        </param-value>
+    </context-param>
+    <locale-encoding-mapping-list>
+        <locale-encoding-mapping>
+            <locale>ar</locale>
+            <encoding>ISO-8859-6</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>be</locale>
+            <encoding>ISO-8859-5</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>bg</locale>
+            <encoding>ISO-8859-5</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>ca</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>cs</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>da</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>de</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>el</locale>
+            <encoding>ISO-8859-7</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>en</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>es</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>et</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>fi</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>fr</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>hr</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>hu</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>is</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>it</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>iw</locale>
+            <encoding>ISO-8859-8</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>ja</locale>
+            <encoding>Shift_JIS</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>ko</locale>
+            <encoding>EUC-KR</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>lt</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>lv</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>mk</locale>
+            <encoding>ISO-8859-5</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>nl</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>no</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>pl</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>pt</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>ro</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>ru</locale>
+            <encoding>ISO-8859-5</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>sh</locale>
+            <encoding>ISO-8859-5</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>sk</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>sl</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>sq</locale>
+            <encoding>ISO-8859-2</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>sr</locale>
+            <encoding>ISO-8859-5</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>sv</locale>
+            <encoding>ISO-8859-1</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>tr</locale>
+            <encoding>ISO-8859-9</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>uk</locale>
+            <encoding>ISO-8859-5</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>zh</locale>
+            <encoding>GB2312</encoding>
+        </locale-encoding-mapping>
+        <locale-encoding-mapping>
+            <locale>zh_TW</locale>
+            <encoding>Big5</encoding>
+        </locale-encoding-mapping>
+    </locale-encoding-mapping-list>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Disable TRACE</web-resource-name>
+            <url-pattern>/</url-pattern>
+            <http-method>TRACE</http-method>
+        </web-resource-collection>
+        <auth-constraint/>
+    </security-constraint>
+</web-app>
+
diff --git a/server/src/main/jetty-config/ning-jetty-conf.xml b/server/src/main/jetty-config/ning-jetty-conf.xml
new file mode 100644
index 0000000..60764c5
--- /dev/null
+++ b/server/src/main/jetty-config/ning-jetty-conf.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+    <!-- =============================================================== -->
+    <!-- Setup MBean Server early                                        -->
+    <!-- =============================================================== -->
+    <Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer"/>
+
+    <New id="MBeanContainer" class="org.eclipse.jetty.jmx.MBeanContainer">
+        <Arg>
+            <Ref id="MBeanServer"/>
+        </Arg>
+    </New>
+
+    <Get id="Container" name="container">
+        <Call name="addEventListener">
+            <Arg>
+                <Ref id="MBeanContainer"/>
+            </Arg>
+        </Call>
+    </Get>
+
+    <!-- =========================================================== -->
+    <!-- Server Thread Pool                                          -->
+    <!-- =========================================================== -->
+    <Set name="ThreadPool">
+        <!-- Default queued blocking threadpool -->
+        <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
+            <Set name="minThreads">
+                <SystemProperty name="xn.server.threads.min" default="10"/>
+            </Set>
+            <Set name="maxThreads">
+                <SystemProperty name="xn.server.threads.max" default="200"/>
+            </Set>
+        </New>
+    </Set>
+
+    <!-- =========================================================== -->
+    <!-- Set connectors                                              -->
+    <!-- =========================================================== -->
+
+    <!-- Use this connector if NIO is not available. -->
+    <Call name="addConnector">
+        <Arg>
+            <New class="org.eclipse.jetty.server.bio.SocketConnector">
+                <Set name="host">
+                    <SystemProperty name="xn.server.ip"/>
+                </Set>
+                <Set name="port">
+                    <SystemProperty name="xn.server.port" default="8080"/>
+                </Set>
+                <Set name="maxIdleTime">300000</Set>
+                <Set name="Acceptors">2</Set>
+                <Set name="statsOn">true</Set>
+                <Set name="confidentialPort">
+                    <SystemProperty name="xn.server.ssl.port" default="8443"/>
+                </Set>
+            </New>
+        </Arg>
+    </Call>
+
+    <Set name="handler">
+        <New class="org.eclipse.jetty.server.handler.StatisticsHandler">
+            <Set name="handler">
+                <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
+                    <Set name="handlers">
+                        <Array type="org.eclipse.jetty.server.Handler">
+                            <Item>
+                                <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
+                            </Item>
+                            <Item>
+                                <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
+                            </Item>
+                            <Item>
+                                <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
+                            </Item>
+                        </Array>
+                    </Set>
+                </New>
+            </Set>
+        </New>
+    </Set>
+
+    <Ref id="RequestLog">
+        <Set name="requestLog">
+            <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
+                <Arg>
+                    <SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log
+                </Arg>
+                <Set name="retainDays">30</Set>
+                <Set name="append">true</Set>
+                <Set name="extended">false</Set>
+                <Set name="LogTimeZone">GMT</Set>
+            </New>
+        </Set>
+    </Ref>
+
+    <Call name="addLifeCycle">
+        <Arg>
+            <New class="org.eclipse.jetty.deploy.ContextDeployer">
+                <Set name="contexts">
+                    <Ref id="Contexts"/>
+                </Set>
+                <Set name="configurationDir">
+                    <SystemProperty name="xn.jetty.contextDir" default="contexts"/>
+                </Set>
+                <Set name="scanInterval">1</Set>
+            </New>
+        </Arg>
+    </Call>
+
+    <!-- =========================================================== -->
+    <!-- extra options                                               -->
+    <!-- =========================================================== -->
+    <Set name="stopAtShutdown">true</Set>
+    <Set name="sendServerVersion">false</Set>
+    <Set name="sendDateHeader">true</Set>
+    <Set name="gracefulShutdown">
+        <SystemProperty name="xn.jetty.gracefulShutdownTimeoutInMs" default="1000"/>
+    </Set>
+</Configure>
diff --git a/server/src/main/resources/catalog-demo.xml b/server/src/main/resources/catalog-demo.xml
new file mode 100644
index 0000000..8a97d57
--- /dev/null
+++ b/server/src/main/resources/catalog-demo.xml
@@ -0,0 +1,641 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ Copyright 2010-2011 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.
+  -->
+
+<!-- 
+Use cases covered so far:
+	Tiered Product (Pistol/Shotgun/Assault-Rifle)
+	Multiple changeEvent plan policies
+	Multiple PlanAlignment (see below, trial add-on alignments and rescue discount package)
+	Product transition rules
+	Add on (Scopes, Hoster)
+	Multi-pack addon (Extra-Ammo)
+	Addon Trial aligned to base plan (holster-monthly-regular)
+	Addon Trial aligned to creation (holster-monthly-special)
+	Rescue discount package (assault-rifle-annual-rescue)
+	Plan phase with a reccurring and a one off (refurbish-maintenance)
+	Phan with more than 2 phase (gunclub discount plans)
+		
+Use Cases to do:
+	Tiered Add On
+	Riskfree period
+	
+
+
+ -->
+<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+
+	<effectiveDate>2011-01-01T00:00:00+00:00</effectiveDate>
+	<catalogName>Firearms</catalogName>
+
+	<currencies>
+		<currency>USD</currency>
+		<currency>EUR</currency>
+		<currency>GBP</currency>
+	</currencies>
+	
+	<products>
+		<product name="Pistol">
+			<category>BASE</category>
+		</product>
+		<product name="Shotgun">
+			<category>BASE</category>
+            <available>
+                <addonProduct>Telescopic-Scope</addonProduct>
+                <addonProduct>Laser-Scope</addonProduct>
+            </available>
+		</product>
+		<product name="Assault-Rifle">
+			<category>BASE</category>
+			<included> 
+				<addonProduct>Telescopic-Scope</addonProduct>
+			</included>
+			<available>
+				<addonProduct>Laser-Scope</addonProduct>
+			</available>
+		</product>
+		<product name="Telescopic-Scope">
+			<category>ADD_ON</category>
+		</product>
+		<product name="Laser-Scope">
+			<category>ADD_ON</category>
+		</product>
+		<product name="Holster">
+			<category>ADD_ON</category>
+		</product>
+		<product name="Extra-Ammo">
+			<category>ADD_ON</category>
+		</product>
+		<product name="Refurbish-Maintenance">
+			<category>ADD_ON</category>
+		</product>
+	</products>
+	 
+	<rules>
+		<changePolicy>
+			<changePolicyCase> 
+				<phaseType>TRIAL</phaseType>
+				<policy>IMMEDIATE</policy>
+			</changePolicyCase>
+            <changePolicyCase> 
+                <toProduct>Assault-Rifle</toProduct>
+                <policy>IMMEDIATE</policy>
+            </changePolicyCase>
+            <changePolicyCase> 
+                <fromProduct>Pistol</fromProduct>            
+                <toProduct>Shotgun</toProduct>
+                <policy>IMMEDIATE</policy>
+            </changePolicyCase>
+			<changePolicyCase> 
+				<toPriceList>rescue</toPriceList>
+				<policy>END_OF_TERM</policy>
+			</changePolicyCase>
+			<changePolicyCase> 
+				<fromBillingPeriod>MONTHLY</fromBillingPeriod>
+				<toBillingPeriod>ANNUAL</toBillingPeriod>
+				<policy>IMMEDIATE</policy>
+			</changePolicyCase>
+			<changePolicyCase> 
+				<fromBillingPeriod>ANNUAL</fromBillingPeriod>
+				<toBillingPeriod>MONTHLY</toBillingPeriod>
+				<policy>END_OF_TERM</policy>
+			</changePolicyCase>
+			<changePolicyCase> 
+				<policy>END_OF_TERM</policy>
+			</changePolicyCase>
+		</changePolicy>
+		<changeAlignment>
+			<changeAlignmentCase>
+				<toPriceList>rescue</toPriceList>
+				<alignment>CHANGE_OF_PLAN</alignment>
+			</changeAlignmentCase>
+			<changeAlignmentCase>
+				<fromPriceList>rescue</fromPriceList>
+				<toPriceList>rescue</toPriceList>
+				<alignment>CHANGE_OF_PRICELIST</alignment>
+			</changeAlignmentCase>
+            <changeAlignmentCase>
+                <alignment>START_OF_SUBSCRIPTION</alignment>
+            </changeAlignmentCase>
+		</changeAlignment>
+		<cancelPolicy>
+			<cancelPolicyCase>
+				<phaseType>TRIAL</phaseType>
+				<policy>IMMEDIATE</policy>
+			</cancelPolicyCase>
+            <cancelPolicyCase>
+                <policy>END_OF_TERM</policy>
+            </cancelPolicyCase>
+		</cancelPolicy>
+		<createAlignment>
+		    <createAlignmentCase>
+		        <product>Laser-Scope</product>
+                <alignment>START_OF_SUBSCRIPTION</alignment>
+            </createAlignmentCase>
+            <createAlignmentCase>
+                <alignment>START_OF_BUNDLE</alignment>
+            </createAlignmentCase>
+		</createAlignment>
+		<billingAlignment>
+			<billingAlignmentCase>
+				<productCategory>ADD_ON</productCategory>
+				<alignment>BUNDLE</alignment>
+			</billingAlignmentCase>
+			<billingAlignmentCase>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<alignment>SUBSCRIPTION</alignment>
+			</billingAlignmentCase>
+			<billingAlignmentCase>
+				<alignment>ACCOUNT</alignment>
+			</billingAlignmentCase>
+		</billingAlignment>
+		<priceList>
+			<priceListCase>
+				<fromPriceList>rescue</fromPriceList>
+				<toPriceList>DEFAULT</toPriceList>
+			</priceListCase>
+		</priceList>
+	</rules>
+
+	<plans>
+		<plan name="pistol-monthly">
+			<product>Pistol</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice> <!-- empty price implies $0 -->
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>GBP</currency><value>29.95</value></price>
+					<price><currency>EUR</currency><value>29.95</value></price> 
+					<price><currency>USD</currency><value>29.95</value></price>								
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="shotgun-monthly">
+			<product>Shotgun</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice></fixedPrice>
+				    <!-- no price implies $0 -->
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+					<number>-1</number>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>249.95</value></price>								
+					<price><currency>EUR</currency><value>149.95</value></price>
+					<price><currency>GBP</currency><value>169.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="assault-rifle-monthly">
+			<product>Assault-Rifle</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>599.95</value></price>								
+					<price><currency>EUR</currency><value>349.95</value></price>
+					<price><currency>GBP</currency><value>399.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="pistol-annual">
+			<product>Pistol</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="shotgun-annual">
+			<product>Shotgun</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>2399.95</value></price>								
+					<price><currency>EUR</currency><value>1499.95</value></price>
+					<price><currency>GBP</currency><value>1699.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="assault-rifle-annual">
+			<product>Assault-Rifle</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>5999.95</value></price>								
+					<price><currency>EUR</currency><value>3499.95</value></price>
+					<price><currency>GBP</currency><value>3999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="pistol-annual-gunclub-discount">
+			<product>Pistol</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>MONTHS</unit>
+						<number>6</number>
+					</duration>
+					<billingPeriod>MONTHLY</billingPeriod>
+					<recurringPrice>
+						<price><currency>USD</currency><value>9.95</value></price>								
+						<price><currency>EUR</currency><value>9.95</value></price>
+						<price><currency>GBP</currency><value>9.95</value></price>
+					</recurringPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="shotgun-annual-gunclub-discount">
+			<product>Shotgun</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>MONTHS</unit>
+						<number>6</number>
+					</duration>
+					<billingPeriod>MONTHLY</billingPeriod>
+					<recurringPrice>
+						<price><currency>USD</currency><value>19.95</value></price>								
+						<price><currency>EUR</currency><value>49.95</value></price>
+						<price><currency>GBP</currency><value>69.95</value></price>
+					</recurringPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>2399.95</value></price>								
+					<price><currency>EUR</currency><value>1499.95</value></price>
+					<price><currency>GBP</currency><value>1699.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="assault-rifle-annual-gunclub-discount">
+			<product>Assault-Rifle</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>MONTHS</unit>
+						<number>6</number>
+					</duration>
+					<billingPeriod>MONTHLY</billingPeriod>
+					<recurringPrice>
+						<price><currency>USD</currency><value>99.95</value></price>								
+						<price><currency>EUR</currency><value>99.95</value></price>
+						<price><currency>GBP</currency><value>99.95</value></price>
+						</recurringPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>5999.95</value></price>								
+					<price><currency>EUR</currency><value>3499.95</value></price>
+					<price><currency>GBP</currency><value>3999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="laser-scope-monthly">
+		<product>Laser-Scope</product>
+           <initialPhases>
+              <phase type="DISCOUNT">
+                 <duration>
+                    <unit>MONTHS</unit>
+                    <number>1</number>
+                  </duration>
+                 <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                      <price><currency>USD</currency><value>999.95</value></price>                             
+                      <price><currency>EUR</currency><value>499.95</value></price>
+                      <price><currency>GBP</currency><value>999.95</value></price>
+                      </recurringPrice>
+                </phase>
+            </initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>1999.95</value></price>								
+					<price><currency>EUR</currency><value>1499.95</value></price>
+					<price><currency>GBP</currency><value>1999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="telescopic-scope-monthly">
+			<product>Telescopic-Scope</product>
+			<initialPhases>
+              <phase type="DISCOUNT">
+                 <duration>
+                    <unit>MONTHS</unit>
+                    <number>1</number>
+                  </duration>
+                 <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                      <price><currency>USD</currency><value>399.95</value></price>                             
+                      <price><currency>EUR</currency><value>299.95</value></price>
+                      <price><currency>GBP</currency><value>399.95</value></price>
+                      </recurringPrice>
+                </phase>
+            </initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>999.95</value></price>								
+					<price><currency>EUR</currency><value>499.95</value></price>
+					<price><currency>GBP</currency><value>999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="extra-ammo-monthly">
+			<product>Extra-Ammo</product>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>999.95</value></price>								
+					<price><currency>EUR</currency><value>499.95</value></price>
+					<price><currency>GBP</currency><value>999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+			<plansAllowedInBundle>-1</plansAllowedInBundle> <!-- arbitrary number of these (multipack) -->
+		</plan>
+		<plan name="holster-monthly-regular">
+			<product>Holster</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="holster-monthly-special">
+			<product>Holster</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="assault-rifle-annual-rescue">
+			<product>Assault-Rifle</product>
+			<initialPhases>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>YEARS</unit>
+						<number>1</number>
+					</duration>
+					<billingPeriod>ANNUAL</billingPeriod>
+					<recurringPrice>
+						<price><currency>USD</currency><value>5999.95</value></price>								
+						<price><currency>EUR</currency><value>3499.95</value></price>
+						<price><currency>GBP</currency><value>3999.95</value></price>
+					</recurringPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>5999.95</value></price>								
+					<price><currency>EUR</currency><value>3499.95</value></price>
+					<price><currency>GBP</currency><value>3999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="refurbish-maintenance">
+			<product>Refurbish-Maintenance</product>
+			<finalPhase type="FIXEDTERM">
+				<duration>
+					<unit>MONTHS</unit>
+					<number>12</number>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+				<fixedPrice>
+					<price><currency>USD</currency><value>599.95</value></price>								
+					<price><currency>EUR</currency><value>599.95</value></price>
+					<price><currency>GBP</currency><value>599.95</value></price>
+				</fixedPrice>
+			</finalPhase>
+		</plan>
+	</plans>
+	<priceLists>
+		<defaultPriceList name="DEFAULT"> 
+			<plans>
+				<plan>pistol-monthly</plan>
+				<plan>shotgun-monthly</plan>
+				<plan>assault-rifle-monthly</plan>
+				<plan>pistol-annual</plan>
+				<plan>shotgun-annual</plan>
+				<plan>assault-rifle-annual</plan>
+				<plan>laser-scope-monthly</plan>
+				<plan>telescopic-scope-monthly</plan>
+				<plan>extra-ammo-monthly</plan>
+				<plan>holster-monthly-regular</plan>
+				<plan>refurbish-maintenance</plan>
+			</plans>
+		</defaultPriceList>
+		<childPriceList name="gunclubDiscount">
+			<plans>
+				<plan>pistol-monthly</plan>
+				<plan>shotgun-monthly</plan>
+				<plan>assault-rifle-monthly</plan>
+				<plan>pistol-annual-gunclub-discount</plan>
+				<plan>shotgun-annual-gunclub-discount</plan>
+				<plan>assault-rifle-annual-gunclub-discount</plan>
+				<plan>holster-monthly-special</plan>
+			</plans>
+		</childPriceList>
+		<childPriceList name="rescue">
+			<plans>
+				<plan>assault-rifle-annual-rescue</plan>
+			</plans>
+		</childPriceList>
+	</priceLists>
+
+</catalog>
diff --git a/server/src/main/resources/killbill-server.properties b/server/src/main/resources/killbill-server.properties
new file mode 100644
index 0000000..daaa110
--- /dev/null
+++ b/server/src/main/resources/killbill-server.properties
@@ -0,0 +1,12 @@
+# Use skeleton properties for server and configure killbill database
+com.ning.jetty.jdbi.url=jdbc:mysql://127.0.0.1:3306/killbill
+com.ning.jetty.jdbi.user=root
+com.ning.jetty.jdbi.password=root
+
+killbill.catalog.uri=file:src/main/resources/catalog-demo.xml
+
+killbill.entitlement.dao.claim.time=60000
+killbill.entitlement.dao.ready.max=1
+killbill.entitlement.engine.notifications.sleep=500
+user.timezone=UTC
+
diff --git a/server/src/main/resources/logback.xml b/server/src/main/resources/logback.xml
new file mode 100644
index 0000000..3087885
--- /dev/null
+++ b/server/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+<configuration>
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <!-- encoders are assigned the type
+         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="info">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>
diff --git a/server/src/main/webapp/WEB-INF/web.xml b/server/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..9891d30
--- /dev/null
+++ b/server/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xmlns="http://java.sun.com/xml/ns/javaee"
+        xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+        version="2.5">
+    <display-name>irs</display-name>
+    <filter>
+        <!-- Guice emulates Servlet API with DI -->
+        <filter-name>guiceFilter</filter-name>
+        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
+    </filter>
+    <filter-mapping>
+        <filter-name>guiceFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+    <listener>
+        <!-- Jersey insists on using java.util.logging (JUL) -->
+        <listener-class>com.ning.jetty.core.listeners.SetupJULBridge</listener-class>
+    </listener>
+    <listener>
+        <!-- Context listener: called at startup time and creates the injector -->
+        <listener-class>com.ning.billing.server.listeners.KillbillGuiceListener</listener-class>
+    </listener>
+    <!-- ServletHandler#handle requires a backend servlet, it won't be used though (handled by Guice) -->
+    <servlet>
+        <servlet-name>log-invalid-resources</servlet-name>
+        <servlet-class>com.ning.jetty.core.servlets.LogInvalidResourcesServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>log-invalid-resources</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
new file mode 100644
index 0000000..4f0a4b2
--- /dev/null
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -0,0 +1,94 @@
+/* 
+ * Copyright 2010-2011 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.jaxrs;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+import javax.ws.rs.core.Response.Status;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
+import com.ning.http.client.Response;
+
+
+public class TestAccount extends TestJaxrsBase {
+
+	private static final Logger log = LoggerFactory.getLogger(TestAccount.class);
+
+
+	@Test(groups="slow", enabled=true)
+	public void testAccountOk() throws Exception {
+		
+		AccountJson input = createAccount("xoxo", "shdgfhwe", "xoxo@yahoo.com");
+		
+		// Retrieves by external key
+		Map<String, String> queryParams = new HashMap<String, String>();
+		queryParams.put(BaseJaxrsResource.QUERY_EXTERNAL_KEY, "shdgfhwe");
+		Response response = doGet(BaseJaxrsResource.ACCOUNTS_PATH, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+		String baseJson = response.getResponseBody();
+		AccountJson objFromJson = mapper.readValue(baseJson, AccountJson.class);
+		Assert.assertTrue(objFromJson.equals(input));
+		
+		// Update Account
+		AccountJson newInput = new AccountJson(objFromJson.getAcountId(),
+				"zozo", 4, objFromJson.getExternalKey(), "rr@google.com", 18, "EUR", "none", "UTC", "bl1", "bh2", "", "ca", "usa", "415-255-2991");
+		baseJson = mapper.writeValueAsString(newInput);
+		final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + objFromJson.getAcountId();
+		response = doPut(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+		baseJson = response.getResponseBody();
+		objFromJson = mapper.readValue(baseJson, AccountJson.class);
+		Assert.assertTrue(objFromJson.equals(newInput));
+	}
+
+
+	@Test(groups="slow", enabled=true)
+	public void testUpdateNonExistentAccount() throws Exception {
+		AccountJson input = getAccountJson("xoxo", "shghaahwe", "xoxo@yahoo.com");
+		String baseJson = mapper.writeValueAsString(input);
+		final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + input.getAcountId();
+		Response response = doPut(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.NO_CONTENT.getStatusCode());
+		String body = response.getResponseBody();
+		Assert.assertEquals(body, "");
+	}
+	
+	
+	@Test(groups="slow", enabled=true)
+	public void testAccountNonExistent() throws Exception {
+		final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/99999999-b103-42f3-8b6e-dd244f1d0747";
+		Response response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.NO_CONTENT.getStatusCode());
+	}
+	
+	@Test(groups="slow", enabled=true)
+	public void testAccountBadAccountId() throws Exception {
+		final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/yo";
+		Response response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.NOT_FOUND.getStatusCode());
+	}
+}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java b/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
new file mode 100644
index 0000000..d340ab8
--- /dev/null
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
@@ -0,0 +1,116 @@
+/* 
+ * Copyright 2010-2011 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.jaxrs;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.codehaus.jackson.type.TypeReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.json.BundleJson;
+import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
+import com.ning.http.client.Response;
+
+public class TestBundle extends TestJaxrsBase {
+
+	private static final Logger log = LoggerFactory.getLogger(TestBundle.class);
+
+
+	
+	@Test(groups="slow", enabled=true)
+	public void testBundleOk() throws Exception {
+
+		AccountJson accountJson = createAccount("xlxl", "shdgfhkkl", "xlxl@yahoo.com");
+		BundleJson bundleJson = createBundle(accountJson.getAcountId(), "12345");
+		
+		// Retrieves by external key
+		Map<String, String> queryParams = new HashMap<String, String>();
+		queryParams.put(BaseJaxrsResource.QUERY_EXTERNAL_KEY, "12345");
+		Response response = doGet(BaseJaxrsResource.BUNDLES_PATH, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+		String baseJson = response.getResponseBody();
+		BundleJson objFromJson = mapper.readValue(baseJson, BundleJson.class);
+		Assert.assertTrue(objFromJson.equals(bundleJson));
+	}
+	
+	
+	@Test(groups="slow", enabled=true)
+	public void testBundleFromAccount() throws Exception {
+
+		AccountJson accountJson = createAccount("xaxa", "saagfhkkl", "xaxa@yahoo.com");
+		BundleJson bundleJson1 = createBundle(accountJson.getAcountId(), "156567");
+		BundleJson bundleJson2 = createBundle(accountJson.getAcountId(), "265658");
+
+		String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAcountId().toString() + "/" + BaseJaxrsResource.BUNDLES;
+		Response response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+		String baseJson = response.getResponseBody();
+		List<BundleJson> objFromJson = mapper.readValue(baseJson, new TypeReference<List<BundleJson>>() {});
+		
+		Collections.sort(objFromJson, new Comparator<BundleJson>() {
+			@Override
+			public int compare(BundleJson o1, BundleJson o2) {
+				return o1.getExternalKey().compareTo(o2.getExternalKey());
+			}
+		});
+		Assert.assertEquals(objFromJson.get(0), bundleJson1);
+		Assert.assertEquals(objFromJson.get(1), bundleJson2);		
+	}
+	
+	@Test(groups="slow", enabled=true)
+	public void testBundleNonExistent() throws Exception {
+		AccountJson accountJson = createAccount("dfdf", "dfdfgfhkkl", "dfdf@yahoo.com");	
+		
+		String uri = BaseJaxrsResource.BUNDLES_PATH + "/99999999-b103-42f3-8b6e-dd244f1d0747";
+		Response response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.NO_CONTENT.getStatusCode());
+		
+		
+		// Retrieves by external key
+		Map<String, String> queryParams = new HashMap<String, String>();
+		queryParams.put(BaseJaxrsResource.QUERY_EXTERNAL_KEY, "56566");
+		response = doGet(BaseJaxrsResource.BUNDLES_PATH, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.NO_CONTENT.getStatusCode());
+		
+		
+		uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAcountId().toString() + "/" + BaseJaxrsResource.BUNDLES;
+		response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+		String baseJson = response.getResponseBody();
+		List<BundleJson> objFromJson = mapper.readValue(baseJson, new TypeReference<List<BundleJson>>() {});
+		Assert.assertNotNull(objFromJson);
+		Assert.assertEquals(objFromJson.size(), 0);
+	}
+
+	@Test(groups="slow", enabled=true)
+	public void testAppNonExistent() throws Exception {
+		String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/99999999-b103-42f3-8b6e-dd244f1d0747/" + BaseJaxrsResource.BUNDLES;
+		Response response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+		Assert.assertEquals(response.getStatusCode(), Status.NO_CONTENT.getStatusCode());	
+	}
+	
+	
+}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
new file mode 100644
index 0000000..fc7ef09
--- /dev/null
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -0,0 +1,406 @@
+/* 
+ * Copyright 2010-2011 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.jaxrs;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.IDBI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterSuite;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeSuite;
+
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.ning.billing.account.glue.AccountModule;
+import com.ning.billing.analytics.setup.AnalyticsModule;
+import com.ning.billing.beatrix.glue.BeatrixModule;
+import com.ning.billing.beatrix.integration.TestBusHandler;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.config.PaymentConfig;
+import com.ning.billing.dbi.DBIProvider;
+import com.ning.billing.dbi.DbiConfig;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.json.BundleJson;
+import com.ning.billing.jaxrs.json.SubscriptionJson;
+import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
+import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
+import com.ning.billing.payment.setup.PaymentModule;
+import com.ning.billing.server.listeners.KillbillGuiceListener;
+import com.ning.billing.server.modules.KillbillServerModule;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.FieldStoreModule;
+import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.TagStoreModule;
+import com.ning.http.client.AsyncCompletionHandler;
+import com.ning.http.client.AsyncHttpClient;
+import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
+import com.ning.http.client.ListenableFuture;
+import com.ning.http.client.Response;
+import com.ning.jetty.core.CoreConfig;
+import com.ning.jetty.core.server.HttpServer;
+
+public class TestJaxrsBase {
+
+    private final static String PLUGIN_NAME = "noop";
+
+    protected static final int DEFAULT_HTTP_TIMEOUT_SEC =  5;
+
+    protected static final Map<String, String> DEFAULT_EMPTY_QUERY = new HashMap<String, String>();
+
+    private static final Logger log = LoggerFactory.getLogger(TestJaxrsBase.class);
+
+    public static final String HEADER_CONTENT_TYPE = "Content-type";
+    public static final String CONTENT_TYPE = "application/json";
+
+    private MysqlTestingHelper helper;
+    private HttpServer server;
+
+
+    // YAck...
+    private static Injector injector;
+
+    protected CoreConfig config;
+    protected AsyncHttpClient httpClient;	
+    protected ObjectMapper mapper;
+    protected ClockMock clock;
+    protected TestBusHandler busHandler;
+
+    public static void loadSystemPropertiesFromClasspath(final String resource) {
+        final URL url = TestJaxrsBase.class.getResource(resource);
+        assertNotNull(url);
+        try {
+            System.getProperties().load(url.openStream());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static class TestKillbillGuiceListener extends KillbillGuiceListener {
+        public TestKillbillGuiceListener() {
+            super();
+        }
+        @Override
+        protected Module getModule() {
+            return new TestKillbillServerModule();
+        }
+        public Injector getTheInjector() {
+            return theInjector;
+        }
+    }
+
+    public static class TestKillbillServerModule extends KillbillServerModule {
+
+        @Override
+        protected void installClock() {
+            bind(Clock.class).to(ClockMock.class).asEagerSingleton();
+        }
+
+
+        private static final class PaymentMockModule extends PaymentModule {
+            @Override
+            protected void installPaymentProviderPlugins(PaymentConfig config) {
+                install(new MockPaymentProviderPluginModule(PLUGIN_NAME));
+            }
+        }
+
+        protected void installKillbillModules(){
+
+            /*
+             * For a lack of getting module override working, copy all install modules from parent class...
+             * 
+            super.installKillbillModules();
+            Modules.override(new com.ning.billing.payment.setup.PaymentModule()).with(new PaymentMockModule());
+            */
+            install(new FieldStoreModule());
+            install(new TagStoreModule());
+            install(new CatalogModule());
+            install(new BusModule());
+            install(new NotificationQueueModule());
+            install(new CallContextModule());
+            install(new AccountModule());
+            install(new InvoiceModule());
+            install(new EntitlementModule());
+            install(new AnalyticsModule());
+            install(new PaymentMockModule());
+            install(new BeatrixModule());
+            installClock();
+        }
+
+        @Override
+        protected void configureDao() {
+            final MysqlTestingHelper helper = new MysqlTestingHelper();
+            bind(MysqlTestingHelper.class).toInstance(helper);
+            if (helper.isUsingLocalInstance()) {
+                bind(IDBI.class).toProvider(DBIProvider.class).asEagerSingleton();
+                final DbiConfig config = new ConfigurationObjectFactory(System.getProperties()).build(DbiConfig.class);
+                bind(DbiConfig.class).toInstance(config);
+            } else {
+                final IDBI dbi = helper.getDBI();
+                bind(IDBI.class).toInstance(dbi);
+            }
+        }
+    }
+
+    @BeforeMethod(groups="slow")
+    public void cleanupTables() {
+        helper.cleanupAllTables();
+        busHandler.reset();
+    }
+
+    @BeforeClass(groups="slow")
+    public void setupClass() {
+
+        loadConfig();
+        httpClient = new AsyncHttpClient();
+        mapper = new ObjectMapper();
+        helper = injector.getInstance(MysqlTestingHelper.class);
+        clock = (ClockMock) injector.getInstance(Clock.class);
+        busHandler = new TestBusHandler();
+    }
+
+
+    private void loadConfig() {
+        if (config == null) {
+            config = new ConfigurationObjectFactory(System.getProperties()).build(CoreConfig.class);
+        }
+    }
+
+    @BeforeSuite(groups="slow")
+    public void setup() throws Exception {
+
+        loadSystemPropertiesFromClasspath("/killbill.properties");
+
+        final EventListener eventListener = new TestKillbillGuiceListener();
+        server = new HttpServer();
+        loadConfig();
+        final Iterable<EventListener> eventListeners = new Iterable<EventListener>() {
+            @Override
+            public Iterator<EventListener> iterator() {
+                ArrayList<EventListener> array = new ArrayList<EventListener>();
+                array.add(eventListener);
+                return array.iterator();
+            }
+        };
+        server.configure(config, eventListeners, new HashMap<FilterHolder, String>());
+        server.start();
+        injector = ((TestKillbillGuiceListener) eventListener).getTheInjector();		
+    }
+
+    @AfterSuite(groups="slow")
+    public void tearDown() {
+        if (helper != null) {
+            helper.stopMysql();
+        }
+        try {
+            server.stop();
+        } catch (Exception e) {
+
+        }
+    }
+
+
+    protected AccountJson createAccount(String name, String key, String email) throws Exception {
+        AccountJson input = getAccountJson(name, key, email);
+        String baseJson = mapper.writeValueAsString(input);
+        Response response = doPost(BaseJaxrsResource.ACCOUNTS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+        String location = response.getHeader("Location");
+        Assert.assertNotNull(location);
+
+        // Retrieves by Id based on Location returned
+        response = doGetWithUrl(location, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+
+        baseJson = response.getResponseBody();
+        AccountJson objFromJson = mapper.readValue(baseJson, AccountJson.class);
+        Assert.assertNotNull(objFromJson);
+        return objFromJson;
+    }
+
+
+
+    protected BundleJson createBundle(String accountId, String key) throws Exception {
+        BundleJson input = new BundleJson(null, accountId, key, null);
+        String baseJson = mapper.writeValueAsString(input);
+        Response response = doPost(BaseJaxrsResource.BUNDLES_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+        String location = response.getHeader("Location");
+        Assert.assertNotNull(location);
+
+        // Retrieves by Id based on Location returned
+        response = doGetWithUrl(location, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+
+        baseJson = response.getResponseBody();
+        BundleJson objFromJson = mapper.readValue(baseJson, BundleJson.class);
+        Assert.assertTrue(objFromJson.equalsNoId(input));
+        return objFromJson;
+    }
+
+    protected SubscriptionJson createSubscription(final String bundleId, final String productName, final String productCategory, final String billingPeriod, final boolean waitCompletion) throws Exception {
+
+        SubscriptionJson input = new SubscriptionJson(null, bundleId, productName, productCategory, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null, null, null);
+        String baseJson = mapper.writeValueAsString(input);
+
+
+        Map<String, String> queryParams = waitCompletion ? getQueryParamsForCallCompletion("5") : DEFAULT_EMPTY_QUERY;
+        Response response = doPost(BaseJaxrsResource.SUBSCRIPTIONS_PATH, baseJson, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+        String location = response.getHeader("Location");
+        Assert.assertNotNull(location);
+
+        // Retrieves by Id based on Location returned
+
+        response = doGetWithUrl(location, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+
+        baseJson = response.getResponseBody();
+        SubscriptionJson objFromJson = mapper.readValue(baseJson, SubscriptionJson.class);
+        Assert.assertTrue(objFromJson.equalsNoId(input));
+        return objFromJson;
+    }
+
+    protected Map<String, String> getQueryParamsForCallCompletion(final String timeoutSec) {
+        Map<String, String> queryParams = new HashMap<String, String>();
+        queryParams.put(BaseJaxrsResource.QUERY_CALL_COMPLETION, "true");
+        queryParams.put(BaseJaxrsResource.QUERY_CALL_TIMEOUT, timeoutSec);
+        return queryParams;
+    }
+
+    //
+    // HTTP CLIENT HELPERS
+    //
+    protected Response doPost(final String uri, final String body, final Map<String, String> queryParams, final int timeoutSec) {
+        BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("POST", getUrlFromUri(uri), queryParams);
+        if (body != null) {
+            builder.setBody(body);
+        }
+        return executeAndWait(builder, timeoutSec);
+    }
+
+    protected Response doPut(final String uri, final String body, final Map<String, String> queryParams, final int timeoutSec) {
+        final String url = String.format("http://%s:%d%s", config.getServerHost(), config.getServerPort(), uri);
+        BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("PUT", url, queryParams);
+        if (body != null) {
+            builder.setBody(body);
+        }
+        return executeAndWait(builder, timeoutSec);
+    }
+
+    protected Response doDelete(final String uri, final Map<String, String> queryParams, final int timeoutSec) {
+        final String url = String.format("http://%s:%d%s", config.getServerHost(), config.getServerPort(), uri);
+        BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("DELETE", url, queryParams);
+        return executeAndWait(builder, timeoutSec);
+    }
+
+    protected Response doGet(final String uri, final Map<String, String> queryParams, final int timeoutSec) {
+        final String url = String.format("http://%s:%d%s", config.getServerHost(), config.getServerPort(), uri);
+        return doGetWithUrl(url, queryParams, timeoutSec);
+    }
+
+    protected Response doGetWithUrl(final String url, final Map<String, String> queryParams, final int timeoutSec) {
+        BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("GET", url, queryParams);
+        return executeAndWait(builder, timeoutSec);
+    }
+
+    private Response executeAndWait(final BoundRequestBuilder builder, final int timeoutSec) {
+        Response response = null;
+        try {
+            ListenableFuture<Response> futureStatus = 
+                builder.execute(new AsyncCompletionHandler<Response>() {
+                    @Override
+                    public Response onCompleted(Response response) throws Exception {
+                        return response;
+                    }
+                });
+            response = futureStatus.get(timeoutSec, TimeUnit.SECONDS);
+        } catch (Exception e) {
+            Assert.fail(e.getMessage());			
+        }
+        Assert.assertNotNull(response);
+        return response;
+    }
+
+    private String getUrlFromUri(final String uri) {
+        return String.format("http://%s:%d%s", config.getServerHost(), config.getServerPort(), uri);
+    }
+
+    private BoundRequestBuilder getBuilderWithHeaderAndQuery(final String verb, final String url, final Map<String, String> queryParams) {
+        BoundRequestBuilder builder = null;
+        if (verb.equals("GET")) {
+            builder = httpClient.prepareGet(url);
+        } else if (verb.equals("POST")) {
+            builder = httpClient.preparePost(url);
+        } else if (verb.equals("PUT")) {
+            builder = httpClient.preparePut(url);			
+        } else if (verb.equals("DELETE")) {
+            builder = httpClient.prepareDelete(url);			
+        }
+        builder.addHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE);
+        for (Entry<String, String> q : queryParams.entrySet()) {
+            builder.addQueryParameter(q.getKey(), q.getValue());
+        }
+        return builder;
+    }
+
+    public AccountJson getAccountJson(final String name, final String externalKey, final String email) {
+        String accountId = UUID.randomUUID().toString();
+        int length = 4;
+        int billCycleDay = 12;
+        String currency = "USD";
+        String paymentProvider = "noop";
+        String timeZone = "UTC";
+        String address1 = "12 rue des ecoles";
+        String address2 = "Poitier";
+        String company = "Renault";
+        String state = "Poitou";
+        String country = "France";
+        String phone = "81 53 26 56";
+
+        AccountJson accountJson = new AccountJson(accountId, name, length, externalKey, email, billCycleDay, currency, paymentProvider, timeZone, address1, address2, company, state, country, phone);
+        return accountJson;
+    }
+}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java b/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
new file mode 100644
index 0000000..3bd2524
--- /dev/null
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
@@ -0,0 +1,115 @@
+/* 
+ * Copyright 2010-2011 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.jaxrs;
+
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.catalog.api.TimeUnit;
+import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.json.BundleJson;
+import com.ning.billing.jaxrs.json.SubscriptionJson;
+import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
+import com.ning.http.client.Response;
+
+public class TestSubscription extends TestJaxrsBase {
+
+    private static final Logger log = LoggerFactory.getLogger(TestSubscription.class);
+
+    private static final long DELAY = 5000;
+    private static final String CALL_COMPLETION_TIMEOUT_SEC = "5";
+    
+
+    @Test(groups="slow", enabled=true)
+    public void testSubscriptionInTrialOk() throws Exception {
+
+        AccountJson accountJson = createAccount("xil", "shdxilhkkl", "xil@yahoo.com");
+        BundleJson bundleJson = createBundle(accountJson.getAcountId(), "99999");
+
+        String productName = "Shotgun";
+        BillingPeriod term = BillingPeriod.MONTHLY;
+
+        SubscriptionJson subscriptionJson = createSubscription(bundleJson.getBundleId(), productName, ProductCategory.BASE.toString(), term.toString(), true);
+
+        // Change plan IMM
+        String newProductName = "Assault-Rifle";
+
+        SubscriptionJson newInput = new SubscriptionJson(subscriptionJson.getSubscriptionId(),
+                subscriptionJson.getBundleId(),
+                newProductName,
+                subscriptionJson.getProductCategory(), 
+                subscriptionJson.getBillingPeriod(), 
+                subscriptionJson.getPriceList(), null, null, null);
+        String baseJson = mapper.writeValueAsString(newInput);
+
+        String uri = BaseJaxrsResource.SUBSCRIPTIONS_PATH + "/" + subscriptionJson.getSubscriptionId().toString();
+        Map<String, String> queryParams = getQueryParamsForCallCompletion(CALL_COMPLETION_TIMEOUT_SEC);
+        Response response = doPut(uri, baseJson, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        baseJson = response.getResponseBody();
+        SubscriptionJson objFromJson = mapper.readValue(baseJson, SubscriptionJson.class);
+        Assert.assertTrue(objFromJson.equals(newInput));
+
+        clock.setDeltaFromReality(new Duration() {
+            @Override
+            public TimeUnit getUnit() {
+                return TimeUnit.MONTHS;
+            }
+            @Override
+            public int getNumber() {
+                return 1;
+            }
+            @Override
+            public DateTime addToDateTime(DateTime dateTime) {
+                return null;
+            }
+        }, 1000);
+
+        crappyWaitForLackOfProperSynchonization();
+
+        //      
+        // Cancel EOT
+        uri = BaseJaxrsResource.SUBSCRIPTIONS_PATH + "/" + subscriptionJson.getSubscriptionId().toString();
+        response = doDelete(uri, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+
+        // Uncancel
+        uri = BaseJaxrsResource.SUBSCRIPTIONS_PATH + "/" + subscriptionJson.getSubscriptionId().toString() + "/uncancel";
+        response = doPut(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+    }
+ 
+
+    /**
+     * 
+     * We could implement a ClockResource in jaxrs with the ability to sync on user token
+     * but until we have a strong need for it, this is in the TODO list...
+     */
+    private void crappyWaitForLackOfProperSynchonization() throws Exception {
+        Thread.sleep(DELAY);
+    }
+
+}
diff --git a/server/src/test/resources/catalog-weapons.xml b/server/src/test/resources/catalog-weapons.xml
new file mode 100644
index 0000000..8a97d57
--- /dev/null
+++ b/server/src/test/resources/catalog-weapons.xml
@@ -0,0 +1,641 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ Copyright 2010-2011 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.
+  -->
+
+<!-- 
+Use cases covered so far:
+	Tiered Product (Pistol/Shotgun/Assault-Rifle)
+	Multiple changeEvent plan policies
+	Multiple PlanAlignment (see below, trial add-on alignments and rescue discount package)
+	Product transition rules
+	Add on (Scopes, Hoster)
+	Multi-pack addon (Extra-Ammo)
+	Addon Trial aligned to base plan (holster-monthly-regular)
+	Addon Trial aligned to creation (holster-monthly-special)
+	Rescue discount package (assault-rifle-annual-rescue)
+	Plan phase with a reccurring and a one off (refurbish-maintenance)
+	Phan with more than 2 phase (gunclub discount plans)
+		
+Use Cases to do:
+	Tiered Add On
+	Riskfree period
+	
+
+
+ -->
+<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+
+	<effectiveDate>2011-01-01T00:00:00+00:00</effectiveDate>
+	<catalogName>Firearms</catalogName>
+
+	<currencies>
+		<currency>USD</currency>
+		<currency>EUR</currency>
+		<currency>GBP</currency>
+	</currencies>
+	
+	<products>
+		<product name="Pistol">
+			<category>BASE</category>
+		</product>
+		<product name="Shotgun">
+			<category>BASE</category>
+            <available>
+                <addonProduct>Telescopic-Scope</addonProduct>
+                <addonProduct>Laser-Scope</addonProduct>
+            </available>
+		</product>
+		<product name="Assault-Rifle">
+			<category>BASE</category>
+			<included> 
+				<addonProduct>Telescopic-Scope</addonProduct>
+			</included>
+			<available>
+				<addonProduct>Laser-Scope</addonProduct>
+			</available>
+		</product>
+		<product name="Telescopic-Scope">
+			<category>ADD_ON</category>
+		</product>
+		<product name="Laser-Scope">
+			<category>ADD_ON</category>
+		</product>
+		<product name="Holster">
+			<category>ADD_ON</category>
+		</product>
+		<product name="Extra-Ammo">
+			<category>ADD_ON</category>
+		</product>
+		<product name="Refurbish-Maintenance">
+			<category>ADD_ON</category>
+		</product>
+	</products>
+	 
+	<rules>
+		<changePolicy>
+			<changePolicyCase> 
+				<phaseType>TRIAL</phaseType>
+				<policy>IMMEDIATE</policy>
+			</changePolicyCase>
+            <changePolicyCase> 
+                <toProduct>Assault-Rifle</toProduct>
+                <policy>IMMEDIATE</policy>
+            </changePolicyCase>
+            <changePolicyCase> 
+                <fromProduct>Pistol</fromProduct>            
+                <toProduct>Shotgun</toProduct>
+                <policy>IMMEDIATE</policy>
+            </changePolicyCase>
+			<changePolicyCase> 
+				<toPriceList>rescue</toPriceList>
+				<policy>END_OF_TERM</policy>
+			</changePolicyCase>
+			<changePolicyCase> 
+				<fromBillingPeriod>MONTHLY</fromBillingPeriod>
+				<toBillingPeriod>ANNUAL</toBillingPeriod>
+				<policy>IMMEDIATE</policy>
+			</changePolicyCase>
+			<changePolicyCase> 
+				<fromBillingPeriod>ANNUAL</fromBillingPeriod>
+				<toBillingPeriod>MONTHLY</toBillingPeriod>
+				<policy>END_OF_TERM</policy>
+			</changePolicyCase>
+			<changePolicyCase> 
+				<policy>END_OF_TERM</policy>
+			</changePolicyCase>
+		</changePolicy>
+		<changeAlignment>
+			<changeAlignmentCase>
+				<toPriceList>rescue</toPriceList>
+				<alignment>CHANGE_OF_PLAN</alignment>
+			</changeAlignmentCase>
+			<changeAlignmentCase>
+				<fromPriceList>rescue</fromPriceList>
+				<toPriceList>rescue</toPriceList>
+				<alignment>CHANGE_OF_PRICELIST</alignment>
+			</changeAlignmentCase>
+            <changeAlignmentCase>
+                <alignment>START_OF_SUBSCRIPTION</alignment>
+            </changeAlignmentCase>
+		</changeAlignment>
+		<cancelPolicy>
+			<cancelPolicyCase>
+				<phaseType>TRIAL</phaseType>
+				<policy>IMMEDIATE</policy>
+			</cancelPolicyCase>
+            <cancelPolicyCase>
+                <policy>END_OF_TERM</policy>
+            </cancelPolicyCase>
+		</cancelPolicy>
+		<createAlignment>
+		    <createAlignmentCase>
+		        <product>Laser-Scope</product>
+                <alignment>START_OF_SUBSCRIPTION</alignment>
+            </createAlignmentCase>
+            <createAlignmentCase>
+                <alignment>START_OF_BUNDLE</alignment>
+            </createAlignmentCase>
+		</createAlignment>
+		<billingAlignment>
+			<billingAlignmentCase>
+				<productCategory>ADD_ON</productCategory>
+				<alignment>BUNDLE</alignment>
+			</billingAlignmentCase>
+			<billingAlignmentCase>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<alignment>SUBSCRIPTION</alignment>
+			</billingAlignmentCase>
+			<billingAlignmentCase>
+				<alignment>ACCOUNT</alignment>
+			</billingAlignmentCase>
+		</billingAlignment>
+		<priceList>
+			<priceListCase>
+				<fromPriceList>rescue</fromPriceList>
+				<toPriceList>DEFAULT</toPriceList>
+			</priceListCase>
+		</priceList>
+	</rules>
+
+	<plans>
+		<plan name="pistol-monthly">
+			<product>Pistol</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice> <!-- empty price implies $0 -->
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>GBP</currency><value>29.95</value></price>
+					<price><currency>EUR</currency><value>29.95</value></price> 
+					<price><currency>USD</currency><value>29.95</value></price>								
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="shotgun-monthly">
+			<product>Shotgun</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice></fixedPrice>
+				    <!-- no price implies $0 -->
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+					<number>-1</number>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>249.95</value></price>								
+					<price><currency>EUR</currency><value>149.95</value></price>
+					<price><currency>GBP</currency><value>169.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="assault-rifle-monthly">
+			<product>Assault-Rifle</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>599.95</value></price>								
+					<price><currency>EUR</currency><value>349.95</value></price>
+					<price><currency>GBP</currency><value>399.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="pistol-annual">
+			<product>Pistol</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="shotgun-annual">
+			<product>Shotgun</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>2399.95</value></price>								
+					<price><currency>EUR</currency><value>1499.95</value></price>
+					<price><currency>GBP</currency><value>1699.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="assault-rifle-annual">
+			<product>Assault-Rifle</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>5999.95</value></price>								
+					<price><currency>EUR</currency><value>3499.95</value></price>
+					<price><currency>GBP</currency><value>3999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="pistol-annual-gunclub-discount">
+			<product>Pistol</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>MONTHS</unit>
+						<number>6</number>
+					</duration>
+					<billingPeriod>MONTHLY</billingPeriod>
+					<recurringPrice>
+						<price><currency>USD</currency><value>9.95</value></price>								
+						<price><currency>EUR</currency><value>9.95</value></price>
+						<price><currency>GBP</currency><value>9.95</value></price>
+					</recurringPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="shotgun-annual-gunclub-discount">
+			<product>Shotgun</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>MONTHS</unit>
+						<number>6</number>
+					</duration>
+					<billingPeriod>MONTHLY</billingPeriod>
+					<recurringPrice>
+						<price><currency>USD</currency><value>19.95</value></price>								
+						<price><currency>EUR</currency><value>49.95</value></price>
+						<price><currency>GBP</currency><value>69.95</value></price>
+					</recurringPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>2399.95</value></price>								
+					<price><currency>EUR</currency><value>1499.95</value></price>
+					<price><currency>GBP</currency><value>1699.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="assault-rifle-annual-gunclub-discount">
+			<product>Assault-Rifle</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>MONTHS</unit>
+						<number>6</number>
+					</duration>
+					<billingPeriod>MONTHLY</billingPeriod>
+					<recurringPrice>
+						<price><currency>USD</currency><value>99.95</value></price>								
+						<price><currency>EUR</currency><value>99.95</value></price>
+						<price><currency>GBP</currency><value>99.95</value></price>
+						</recurringPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>5999.95</value></price>								
+					<price><currency>EUR</currency><value>3499.95</value></price>
+					<price><currency>GBP</currency><value>3999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="laser-scope-monthly">
+		<product>Laser-Scope</product>
+           <initialPhases>
+              <phase type="DISCOUNT">
+                 <duration>
+                    <unit>MONTHS</unit>
+                    <number>1</number>
+                  </duration>
+                 <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                      <price><currency>USD</currency><value>999.95</value></price>                             
+                      <price><currency>EUR</currency><value>499.95</value></price>
+                      <price><currency>GBP</currency><value>999.95</value></price>
+                      </recurringPrice>
+                </phase>
+            </initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>1999.95</value></price>								
+					<price><currency>EUR</currency><value>1499.95</value></price>
+					<price><currency>GBP</currency><value>1999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="telescopic-scope-monthly">
+			<product>Telescopic-Scope</product>
+			<initialPhases>
+              <phase type="DISCOUNT">
+                 <duration>
+                    <unit>MONTHS</unit>
+                    <number>1</number>
+                  </duration>
+                 <billingPeriod>MONTHLY</billingPeriod>
+                    <recurringPrice>
+                      <price><currency>USD</currency><value>399.95</value></price>                             
+                      <price><currency>EUR</currency><value>299.95</value></price>
+                      <price><currency>GBP</currency><value>399.95</value></price>
+                      </recurringPrice>
+                </phase>
+            </initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>999.95</value></price>								
+					<price><currency>EUR</currency><value>499.95</value></price>
+					<price><currency>GBP</currency><value>999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="extra-ammo-monthly">
+			<product>Extra-Ammo</product>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>999.95</value></price>								
+					<price><currency>EUR</currency><value>499.95</value></price>
+					<price><currency>GBP</currency><value>999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+			<plansAllowedInBundle>-1</plansAllowedInBundle> <!-- arbitrary number of these (multipack) -->
+		</plan>
+		<plan name="holster-monthly-regular">
+			<product>Holster</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="holster-monthly-special">
+			<product>Holster</product>
+			<initialPhases>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="assault-rifle-annual-rescue">
+			<product>Assault-Rifle</product>
+			<initialPhases>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>YEARS</unit>
+						<number>1</number>
+					</duration>
+					<billingPeriod>ANNUAL</billingPeriod>
+					<recurringPrice>
+						<price><currency>USD</currency><value>5999.95</value></price>								
+						<price><currency>EUR</currency><value>3499.95</value></price>
+						<price><currency>GBP</currency><value>3999.95</value></price>
+					</recurringPrice>
+				</phase>
+			</initialPhases>
+			<finalPhase type="EVERGREEN">
+				<duration>
+					<unit>UNLIMITED</unit>
+				</duration>
+				<billingPeriod>ANNUAL</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>5999.95</value></price>								
+					<price><currency>EUR</currency><value>3499.95</value></price>
+					<price><currency>GBP</currency><value>3999.95</value></price>
+				</recurringPrice>
+			</finalPhase>
+		</plan>
+		<plan name="refurbish-maintenance">
+			<product>Refurbish-Maintenance</product>
+			<finalPhase type="FIXEDTERM">
+				<duration>
+					<unit>MONTHS</unit>
+					<number>12</number>
+				</duration>
+				<billingPeriod>MONTHLY</billingPeriod>
+				<recurringPrice>
+					<price><currency>USD</currency><value>199.95</value></price>								
+					<price><currency>EUR</currency><value>199.95</value></price>
+					<price><currency>GBP</currency><value>199.95</value></price>
+				</recurringPrice>
+				<fixedPrice>
+					<price><currency>USD</currency><value>599.95</value></price>								
+					<price><currency>EUR</currency><value>599.95</value></price>
+					<price><currency>GBP</currency><value>599.95</value></price>
+				</fixedPrice>
+			</finalPhase>
+		</plan>
+	</plans>
+	<priceLists>
+		<defaultPriceList name="DEFAULT"> 
+			<plans>
+				<plan>pistol-monthly</plan>
+				<plan>shotgun-monthly</plan>
+				<plan>assault-rifle-monthly</plan>
+				<plan>pistol-annual</plan>
+				<plan>shotgun-annual</plan>
+				<plan>assault-rifle-annual</plan>
+				<plan>laser-scope-monthly</plan>
+				<plan>telescopic-scope-monthly</plan>
+				<plan>extra-ammo-monthly</plan>
+				<plan>holster-monthly-regular</plan>
+				<plan>refurbish-maintenance</plan>
+			</plans>
+		</defaultPriceList>
+		<childPriceList name="gunclubDiscount">
+			<plans>
+				<plan>pistol-monthly</plan>
+				<plan>shotgun-monthly</plan>
+				<plan>assault-rifle-monthly</plan>
+				<plan>pistol-annual-gunclub-discount</plan>
+				<plan>shotgun-annual-gunclub-discount</plan>
+				<plan>assault-rifle-annual-gunclub-discount</plan>
+				<plan>holster-monthly-special</plan>
+			</plans>
+		</childPriceList>
+		<childPriceList name="rescue">
+			<plans>
+				<plan>assault-rifle-annual-rescue</plan>
+			</plans>
+		</childPriceList>
+	</priceLists>
+
+</catalog>
diff --git a/server/src/test/resources/killbill.properties b/server/src/test/resources/killbill.properties
new file mode 100644
index 0000000..2ff0814
--- /dev/null
+++ b/server/src/test/resources/killbill.properties
@@ -0,0 +1,16 @@
+# Use killbill util test properties (DbiProvider/MysqltestingHelper) on the test side configured with test_killbill
+com.ning.billing.dbi.jdbc.url=jdbc:mysql://127.0.0.1:3306/test_killbill
+
+killbill.catalog.uri=file:src/test/resources/catalog-weapons.xml
+
+killbill.payment.engine.events.off=false
+killbill.payment.retry.days=8,8,8
+
+user.timezone=UTC
+
+com.ning.billing.dbi.test.useLocalDb=true
+
+com.ning.core.server.jetty.logPath=/var/tmp/.logs
+
+
+
diff --git a/server/src/test/resources/log4j.xml b/server/src/test/resources/log4j.xml
new file mode 100644
index 0000000..0c84cc0
--- /dev/null
+++ b/server/src/test/resources/log4j.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2010-2011 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.
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+        <param name="Target" value="System.out"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%p	%d{ISO8601}	%X{trace}	%t	%c	%m%n"/>
+        </layout>
+    </appender>
+
+
+    <logger name="com.ning.billing.jaxrs">
+        <level value="debug"/>
+    </logger>
+    <logger name="com.ning.billing.server">
+        <level value="info"/>
+    </logger>
+
+    <root>
+        <priority value="info"/>
+        <appender-ref ref="stdout"/>
+    </root>
+</log4j:configuration>
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/CallContextBase.java b/util/src/main/java/com/ning/billing/util/callcontext/CallContextBase.java
index 8164f76..35dc92f 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/CallContextBase.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/CallContextBase.java
@@ -16,15 +16,25 @@
 
 package com.ning.billing.util.callcontext;
 
+import java.util.UUID;
+
 public abstract class CallContextBase implements CallContext {
+	
+	private final UUID userToken;
     private final String userName;
     private final CallOrigin callOrigin;
     private final UserType userType;
 
+
     public CallContextBase(String userName, CallOrigin callOrigin, UserType userType) {
+    	this(userName, callOrigin, userType, null);
+    }
+
+    public CallContextBase(String userName, CallOrigin callOrigin, UserType userType, UUID userToken) {
         this.userName = userName;
         this.callOrigin = callOrigin;
         this.userType = userType;
+        this.userToken = userToken;
     }
 
     @Override
@@ -41,4 +51,9 @@ public abstract class CallContextBase implements CallContext {
     public UserType getUserType() {
         return userType;
     }
+    
+    @Override
+    public UUID getUserToken() {
+    	return userToken;
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/CallContextBinder.java b/util/src/main/java/com/ning/billing/util/callcontext/CallContextBinder.java
index 3ac8a98..41dd68a 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/CallContextBinder.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/CallContextBinder.java
@@ -37,9 +37,10 @@ public @interface CallContextBinder {
             return new Binder<CallContextBinder, CallContext>() {
                 @Override
                 public void bind(SQLStatement q, CallContextBinder bind, CallContext callContext) {
-                    q.bind("userName", callContext.getUserName());
+                	q.bind("userName", callContext.getUserName());
                     q.bind("createdDate", callContext.getCreatedDate().toDate());
                     q.bind("updatedDate", callContext.getUpdatedDate().toDate());
+                	q.bind("userToken", (callContext.getUserToken() != null) ? callContext.getUserToken().toString() : null);                	
                 }
             };
         }
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/CallContextFactory.java b/util/src/main/java/com/ning/billing/util/callcontext/CallContextFactory.java
index 6ffc554..d9f18c9 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/CallContextFactory.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/CallContextFactory.java
@@ -16,10 +16,14 @@
 
 package com.ning.billing.util.callcontext;
 
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 
 public interface CallContextFactory {
-    CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType);
+    CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType, UUID userToken);
+    
+    CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType);    
 
     CallContext createMigrationCallContext(String userName, CallOrigin callOrigin, UserType userType, DateTime createdDate, DateTime updatedDate);
 
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
index 57dc682..4cde143 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
@@ -16,17 +16,24 @@
 
 package com.ning.billing.util.callcontext;
 
+import java.util.UUID;
+
 import com.ning.billing.util.clock.Clock;
 import org.joda.time.DateTime;
 
 public class DefaultCallContext extends CallContextBase {
+	
     private final Clock clock;
 
-    public DefaultCallContext(String userName, CallOrigin callOrigin, UserType userType, Clock clock) {
-        super(userName, callOrigin, userType);
+    public DefaultCallContext(final String userName, final CallOrigin callOrigin, final UserType userType, final UUID userToken, final Clock clock) {
+        super(userName, callOrigin, userType, userToken);
         this.clock = clock;
     }
 
+    public DefaultCallContext(String userName, CallOrigin callOrigin, UserType userType, Clock clock) {
+    	this(userName, callOrigin, userType, null, clock);
+    }
+
     @Override
     public DateTime getCreatedDate() {
         return clock.getUTCNow();
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContextFactory.java b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContextFactory.java
index f75574c..52ac313 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContextFactory.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContextFactory.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.util.callcontext;
 
+import java.util.UUID;
+
 import com.google.inject.Inject;
 import com.ning.billing.util.clock.Clock;
 import org.joda.time.DateTime;
@@ -29,8 +31,13 @@ public class DefaultCallContextFactory implements CallContextFactory {
     }
 
     @Override
+    public CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType, UUID userToken) {
+        return new DefaultCallContext(userName, callOrigin, userType, userToken, clock);
+    }
+
+    @Override
     public CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType) {
-        return new DefaultCallContext(userName, callOrigin, userType, clock);
+    	return createCallContext(userName, callOrigin, userType, null);
     }
 
     @Override
diff --git a/util/src/main/java/com/ning/billing/util/clock/Clock.java b/util/src/main/java/com/ning/billing/util/clock/Clock.java
index b41a36d..6b65aac 100644
--- a/util/src/main/java/com/ning/billing/util/clock/Clock.java
+++ b/util/src/main/java/com/ning/billing/util/clock/Clock.java
@@ -25,6 +25,5 @@ public interface Clock {
 
     public DateTime getUTCNow();
 
-
     //public DateTime addDuration(DateTime input, IDuration duration);
 }
diff --git a/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java b/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
index 8280a15..057a58c 100644
--- a/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
+++ b/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
@@ -36,6 +36,13 @@ public class DefaultClock implements Clock {
         return getNow(DateTimeZone.UTC);
     }
 
+    public static DateTime toUTCDateTime(DateTime input) {
+        if (input == null) {
+            return null;
+        }
+        DateTime result = input.toDateTime(DateTimeZone.UTC);
+        return truncateMs(result);
+    }
 
     public static DateTime truncateMs(DateTime input) {
         return input.minus(input.getMillisOfSecond());
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
index a0e1827..392a218 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
@@ -25,6 +25,7 @@ import org.joda.time.DateTime;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
 import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueueService.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueueService.java
index 3b96ee4..bf8652c 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueueService.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueueService.java
@@ -18,6 +18,7 @@ package com.ning.billing.util.notificationq;
 
 import org.skife.jdbi.v2.IDBI;
 import com.google.inject.Inject;
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.util.clock.Clock;
 
 public class DefaultNotificationQueueService extends NotificationQueueServiceBase {
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
index a4f4c97..eb3f269 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
@@ -26,6 +26,7 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.util.Hostname;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueService.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueService.java
index 4d56b03..828608a 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueService.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueService.java
@@ -18,6 +18,8 @@ package com.ning.billing.util.notificationq;
 
 import org.joda.time.DateTime;
 
+import com.ning.billing.config.NotificationConfig;
+
 
 public interface NotificationQueueService {
 
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueServiceBase.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueServiceBase.java
index 56423a0..90c27b0 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueServiceBase.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueServiceBase.java
@@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Joiner;
 import com.google.inject.Inject;
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.util.clock.Clock;
 
 public abstract class NotificationQueueServiceBase implements NotificationQueueService {
diff --git a/util/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestBase.java b/util/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestBase.java
new file mode 100644
index 0000000..10983d8
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestBase.java
@@ -0,0 +1,156 @@
+/* 
+ * Copyright 2010-2011 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.util.userrequest;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeoutException;
+
+import com.ning.billing.account.api.AccountChangeEvent;
+import com.ning.billing.account.api.AccountCreationEvent;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
+import com.ning.billing.invoice.api.EmptyInvoiceEvent;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.payment.api.PaymentErrorEvent;
+import com.ning.billing.payment.api.PaymentInfoEvent;
+import com.ning.billing.util.bus.BusEvent;
+
+public abstract class CompletionUserRequestBase implements CompletionUserRequest {
+
+    private static final long NANO_TO_MILLI_SEC = (1000L * 1000L);
+
+    private final List<BusEvent> events;
+
+    private final UUID userToken;
+    private long timeoutMilliSec;
+
+    private boolean isCompleted;
+    private long initialTimeMilliSec;
+
+
+    public CompletionUserRequestBase(final UUID userToken) {
+        this.events = new LinkedList<BusEvent>();
+        this.userToken = userToken;
+        this.isCompleted = false;
+    }
+
+    @Override
+    public List<BusEvent> waitForCompletion(final long timeoutMilliSec) throws InterruptedException, TimeoutException {
+
+        this.timeoutMilliSec = timeoutMilliSec;
+        initialTimeMilliSec = currentTimeMillis();
+        synchronized(this) {
+            long remainingTimeMillisSec = getRemainingTimeMillis();
+            while (!isCompleted && remainingTimeMillisSec > 0) {
+                wait(remainingTimeMillisSec);
+                if (isCompleted) {
+                    break;
+                }
+                remainingTimeMillisSec = getRemainingTimeMillis();
+            }
+            if (!isCompleted) {
+                throw new TimeoutException();
+            }
+        }
+        return events;
+    }
+
+    @Override
+    public void notifyForCompletion() {
+        synchronized(this) {
+            isCompleted = true;
+            notify();
+        }
+    }
+
+    private long currentTimeMillis() {
+        return System.nanoTime() / NANO_TO_MILLI_SEC;
+    }
+
+    private long getRemainingTimeMillis() {
+        return timeoutMilliSec - (currentTimeMillis() - initialTimeMilliSec);
+    }
+
+    @Override
+    public void onBusEvent(BusEvent curEvent) {
+        // Check if this is for us..
+        if (curEvent.getUserToken() == null ||
+                ! curEvent.getUserToken().equals(userToken)) {
+            return;
+        }
+        
+        events.add(curEvent);
+        
+        switch(curEvent.getBusEventType()) {
+        case ACCOUNT_CREATE:
+            onAccountCreation((AccountCreationEvent) curEvent);
+            break;
+        case ACCOUNT_CHANGE:
+            onAccountChange((AccountChangeEvent) curEvent);
+            break;
+        case SUBSCRIPTION_TRANSITION:
+            onSubscriptionTransition((SubscriptionEventTransition) curEvent);
+            break;
+        case INVOICE_EMPTY:
+            onEmptyInvoice((EmptyInvoiceEvent) curEvent);
+            break;
+        case INVOICE_CREATION:
+            onInvoiceCreation((InvoiceCreationEvent) curEvent);
+            break;
+        case PAYMENT_INFO:
+            onPaymentInfo((PaymentInfoEvent) curEvent);
+            break;
+        case PAYMENT_ERROR:
+            onPaymentError((PaymentErrorEvent) curEvent);
+            break;
+        default:
+            throw new RuntimeException("Unexpected event type " + curEvent.getBusEventType());
+        }
+    }
+
+    /*
+     * 
+     * Default no-op implementation so as to not have to implement all callbacks
+     */
+    @Override
+    public void onAccountCreation(final AccountCreationEvent curEvent) {
+    }
+
+    @Override
+    public void onAccountChange(final AccountChangeEvent curEvent) {
+    }
+
+    @Override
+    public void onSubscriptionTransition(final SubscriptionEventTransition curEvent) {
+    }
+
+    @Override
+    public void onEmptyInvoice(final EmptyInvoiceEvent curEvent) {
+    }
+    
+    @Override
+    public void onInvoiceCreation(final InvoiceCreationEvent curEvent) {
+    }
+
+    @Override
+    public void onPaymentInfo(final PaymentInfoEvent curEvent) {
+    }
+
+    @Override
+    public void onPaymentError(final PaymentErrorEvent curEvent) {
+    }
+}
diff --git a/util/src/main/resources/com/ning/billing/util/audit/dao/AuditSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/audit/dao/AuditSqlDao.sql.stg
index 25cc9d4..f949ba8 100644
--- a/util/src/main/resources/com/ning/billing/util/audit/dao/AuditSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/audit/dao/AuditSqlDao.sql.stg
@@ -7,10 +7,11 @@ fields(prefix) ::= <<
     <prefix>change_date,
     <prefix>changed_by,
     <prefix>reason_code,
-    <prefix>comments
+    <prefix>comments,
+    <prefix>user_token
 >>
 
 insertAuditFromTransaction() ::= <<
     INSERT INTO audit_log(<fields()>)
-    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL);
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, :userToken);
 >>
\ No newline at end of file
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index a2ef08f..5ee4089 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -116,15 +116,8 @@ CREATE TABLE audit_log (
     changed_by varchar(50) NOT NULL,
     reason_code varchar(20) DEFAULT NULL,
     comments varchar(255) DEFAULT NULL,
+    user_token char(36),
     PRIMARY KEY(id)
 ) ENGINE=innodb;
 
-DROP TABLE IF EXISTS overdue_states;
-CREATE TABLE overdue_states (
-  id char(36) NOT NULL,
-  state varchar(50) NOT NULL,
-  type varchar(20) NOT NULL,    
-  created_date datetime NOT NULL
-) ENGINE=innodb;
-CREATE INDEX overdue_states_by_id ON overdue_states (id);
 
diff --git a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
index 866289e..9995229 100644
--- a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
+++ b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
@@ -20,6 +20,7 @@ import java.io.File;
 import java.io.IOException;
 import java.net.ServerSocket;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.io.FileUtils;
@@ -27,6 +28,7 @@ import org.skife.jdbi.v2.DBI;
 import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.tweak.HandleCallback;
+import org.skife.jdbi.v2.util.StringMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -48,6 +50,8 @@ public class MysqlTestingHelper
     private static final String USERNAME = "root";
     private static final String PASSWORD = "root";
 
+    // Discover dynamically list of all tables in that database;
+    private List<String> allTables;    
     private File dbDir;
     private MysqldResource mysqldResource;
     private int port;
@@ -122,7 +126,36 @@ public class MysqlTestingHelper
             }
         });
     }
+    
+    public void cleanupAllTables() {
+    	final List<String> tablesToCleanup = fetchAllTables();
+    	for (String tableName : tablesToCleanup) {
+    		cleanupTable(tableName);
+    	}
+    }
+
+    public synchronized List<String> fetchAllTables() {
+
+    	if (allTables == null) {
+    		final String dbiString = "jdbc:mysql://localhost:" + port + "/information_schema";
+    		IDBI cleanupDbi = new DBI(dbiString, USERNAME, PASSWORD);
+
+    		final List<String> tables=  cleanupDbi.withHandle(new HandleCallback<List<String>>() {
+
+    			@Override
+    			public List<String> withHandle(Handle h) throws Exception {
+    				return h.createQuery("select table_name from tables where table_schema = :table_schema and table_type = 'BASE TABLE';")
+    				.bind("table_schema", DB_NAME)
+    				.map(new StringMapper())
+    				.list();
+    			}
+    		});
+    		allTables = tables;
+    	}
+    	return allTables;
+    }
 
+    
     public void stopMysql()
     {
         if (mysqldResource != null) {
diff --git a/util/src/test/java/com/ning/billing/util/bus/TestEventBus.java b/util/src/test/java/com/ning/billing/util/bus/TestEventBus.java
index 2310f1c..a4b493f 100644
--- a/util/src/test/java/com/ning/billing/util/bus/TestEventBus.java
+++ b/util/src/test/java/com/ning/billing/util/bus/TestEventBus.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.util.bus;
 
+import java.util.UUID;
+
 import com.google.common.eventbus.Subscribe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,6 +52,16 @@ public class TestEventBus {
             this.name = name;
             this.value = value;
         }
+
+		@Override
+		public BusEventType getBusEventType() {
+			return null;
+		}
+
+		@Override
+		public UUID getUserToken() {
+			return null;
+		}
     }
 
     public static final class MyOtherEvent implements BusEvent {
@@ -60,6 +72,16 @@ public class TestEventBus {
             this.name = name;
             this.value = value;
         }
+
+		@Override
+		public BusEventType getBusEventType() {
+			return null;
+		}
+
+		@Override
+		public UUID getUserToken() {
+			return null;
+		}
     }
 
     public static class MyEventHandler {
diff --git a/util/src/test/java/com/ning/billing/util/callcontext/TestCallContext.java b/util/src/test/java/com/ning/billing/util/callcontext/TestCallContext.java
index b632f2e..0185a69 100644
--- a/util/src/test/java/com/ning/billing/util/callcontext/TestCallContext.java
+++ b/util/src/test/java/com/ning/billing/util/callcontext/TestCallContext.java
@@ -16,25 +16,27 @@
 
 package com.ning.billing.util.callcontext;
 
+import java.util.UUID;
+
 import com.ning.billing.util.clock.DefaultClock;
 import org.joda.time.DateTime;
 
 public class TestCallContext implements CallContext {
+	
     private final String userName;
     private final DateTime updatedDate;
     private final DateTime createdDate;
-
+    private final UUID userToken;
+    
     public TestCallContext(String userName) {
-        this.userName = userName;
-        DateTime now = new DefaultClock().getUTCNow();
-        this.updatedDate = now;
-        this.createdDate = now;
+    	this(userName, new DefaultClock().getUTCNow(), new DefaultClock().getUTCNow());
     }
 
     public TestCallContext(String userName, DateTime createdDate, DateTime updatedDate) {
         this.userName = userName;
         this.createdDate = createdDate;
         this.updatedDate = updatedDate;
+        this.userToken = UUID.randomUUID();
     }
 
     @Override
@@ -61,4 +63,9 @@ public class TestCallContext implements CallContext {
     public DateTime getUpdatedDate() {
         return updatedDate;
     }
+
+	@Override
+	public UUID getUserToken() {
+		return userToken;
+	}
 }
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
index c78c772..a9cd1db 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
@@ -26,6 +26,7 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.notificationq.NotificationLifecycle.NotificationLifecycleState;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueueService.java b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueueService.java
index e9ce90e..9af43c1 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueueService.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueueService.java
@@ -17,6 +17,7 @@
 package com.ning.billing.util.notificationq;
 
 import com.google.inject.Inject;
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.util.clock.Clock;
 
 public class MockNotificationQueueService extends NotificationQueueServiceBase {
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
index bdd7689..1a9654c 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
@@ -50,6 +50,7 @@ import com.google.common.collect.Collections2;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.name.Names;
+import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;