killbill-memoizeit

Merge branch 'integration' of github.com:ning/killbill

7/1/2012 8:37:07 PM

Changes

overdue/pom.xml 5(+5 -0)

Details

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 8e162f7..9e7faf8 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
@@ -140,11 +140,11 @@ public class AuditedAccountDao implements AccountDao {
                     transactional.update(account, context);
 
                     final Long recordId = accountSqlDao.getRecordId(accountId.toString());
-                    final EntityHistory<Account> history = new EntityHistory<Account>(accountId, recordId, account, ChangeType.INSERT);
+                    final EntityHistory<Account> history = new EntityHistory<Account>(accountId, recordId, account, ChangeType.UPDATE);
                     accountSqlDao.insertHistoryFromTransaction(history, context);
 
                     final Long historyRecordId = accountSqlDao.getHistoryRecordId(recordId);
-                    final EntityAudit audit = new EntityAudit(TableName.ACCOUNT_HISTORY, historyRecordId, ChangeType.INSERT);
+                    final EntityAudit audit = new EntityAudit(TableName.ACCOUNT_HISTORY, historyRecordId, ChangeType.UPDATE);
                     accountSqlDao.insertAuditFromTransaction(audit, context);
 
                     final AccountChangeEvent changeEvent = new DefaultAccountChangeEvent(accountId, context.getUserToken(), currentAccount, account);
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 eb41bce..87a7060 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
@@ -22,8 +22,8 @@ import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountChangeEvent;
 import com.ning.billing.account.api.AccountCreationEvent;
 import com.ning.billing.entitlement.api.timeline.RepairEntitlementEvent;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.invoice.api.EmptyInvoiceEvent;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.payment.api.PaymentErrorEvent;
@@ -55,31 +55,31 @@ public class AnalyticsListener {
     }
 
     @Subscribe
-    public void handleSubscriptionTransitionChange(final SubscriptionEvent event) throws AccountApiException, EntitlementUserApiException {
-        switch (event.getTransitionType()) {
+    public void handleSubscriptionTransitionChange(final EffectiveSubscriptionEvent eventEffective) throws AccountApiException, EntitlementUserApiException {
+        switch (eventEffective.getTransitionType()) {
             // A subscription enters either through migration or as newly created subscription
             case MIGRATE_ENTITLEMENT:
             case CREATE:
-                bstRecorder.subscriptionCreated(event);
+                bstRecorder.subscriptionCreated(eventEffective);
                 break;
             case RE_CREATE:
-                bstRecorder.subscriptionRecreated(event);
+                bstRecorder.subscriptionRecreated(eventEffective);
                 break;
             case MIGRATE_BILLING:
                 break;
             case CANCEL:
-                bstRecorder.subscriptionCancelled(event);
+                bstRecorder.subscriptionCancelled(eventEffective);
                 break;
             case CHANGE:
-                bstRecorder.subscriptionChanged(event);
+                bstRecorder.subscriptionChanged(eventEffective);
                 break;
             case UNCANCEL:
                 break;
             case PHASE:
-                bstRecorder.subscriptionPhaseChanged(event);
+                bstRecorder.subscriptionPhaseChanged(eventEffective);
                 break;
             default:
-                throw new RuntimeException("Unexpected event type " + event.getTransitionType());
+                throw new RuntimeException("Unexpected event type " + eventEffective.getTransitionType());
         }
     }
 
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 04e3547..49d6a9d 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
@@ -32,10 +32,10 @@ import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
 import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 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.SubscriptionEvent;
 
 public class BusinessSubscriptionTransitionRecorder {
     private static final Logger log = LoggerFactory.getLogger(BusinessSubscriptionTransitionRecorder.class);
@@ -54,36 +54,36 @@ public class BusinessSubscriptionTransitionRecorder {
     }
 
 
-    public void subscriptionCreated(final SubscriptionEvent created) throws AccountApiException, EntitlementUserApiException {
+    public void subscriptionCreated(final EffectiveSubscriptionEvent created) throws AccountApiException, EntitlementUserApiException {
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionCreated(created.getNextPlan(), catalogService.getFullCatalog(), created.getEffectiveTransitionTime(), created.getSubscriptionStartDate());
         recordTransition(event, created);
     }
 
 
-    public void subscriptionRecreated(final SubscriptionEvent recreated) throws AccountApiException, EntitlementUserApiException {
+    public void subscriptionRecreated(final EffectiveSubscriptionEvent recreated) throws AccountApiException, EntitlementUserApiException {
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionRecreated(recreated.getNextPlan(), catalogService.getFullCatalog(), recreated.getEffectiveTransitionTime(), recreated.getSubscriptionStartDate());
         recordTransition(event, recreated);
     }
 
 
-    public void subscriptionCancelled(final SubscriptionEvent cancelled) throws AccountApiException, EntitlementUserApiException {
+    public void subscriptionCancelled(final EffectiveSubscriptionEvent cancelled) throws AccountApiException, EntitlementUserApiException {
         // 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(), catalogService.getFullCatalog(), cancelled.getEffectiveTransitionTime(), cancelled.getSubscriptionStartDate());
         recordTransition(event, cancelled);
     }
 
 
-    public void subscriptionChanged(final SubscriptionEvent changed) throws AccountApiException, EntitlementUserApiException {
+    public void subscriptionChanged(final EffectiveSubscriptionEvent changed) throws AccountApiException, EntitlementUserApiException {
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionChanged(changed.getNextPlan(), catalogService.getFullCatalog(), changed.getEffectiveTransitionTime(), changed.getSubscriptionStartDate());
         recordTransition(event, changed);
     }
 
-    public void subscriptionPhaseChanged(final SubscriptionEvent phaseChanged) throws AccountApiException, EntitlementUserApiException {
+    public void subscriptionPhaseChanged(final EffectiveSubscriptionEvent phaseChanged) throws AccountApiException, EntitlementUserApiException {
         final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionPhaseChanged(phaseChanged.getNextPlan(), phaseChanged.getNextState(), catalogService.getFullCatalog(), phaseChanged.getEffectiveTransitionTime(), phaseChanged.getSubscriptionStartDate());
         recordTransition(event, phaseChanged);
     }
 
-    void recordTransition(final BusinessSubscriptionEvent event, final SubscriptionEvent transition)
+    void recordTransition(final BusinessSubscriptionEvent event, final EffectiveSubscriptionEvent transition)
             throws AccountApiException, EntitlementUserApiException {
         Currency currency = null;
         String externalKey = 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 5d452e1..ad54c53 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
@@ -57,12 +57,12 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.user.DefaultSubscriptionEvent;
+import com.ning.billing.entitlement.api.user.DefaultEffectiveSubscriptionEvent;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 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.SubscriptionEvent;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
@@ -126,7 +126,7 @@ public class TestAnalyticsService extends TestWithEmbeddedDB {
     @Inject
     private BusinessAccountSqlDao accountSqlDao;
 
-    private SubscriptionEvent transition;
+    private EffectiveSubscriptionEvent transition;
     private BusinessSubscriptionTransition expectedTransition;
 
     private AccountCreationEvent accountCreationNotification;
@@ -181,7 +181,7 @@ public class TestAnalyticsService extends TestWithEmbeddedDB {
         final PriceList priceList = new MockPriceList().setName("something");
 
 
-        transition = new DefaultSubscriptionEvent(new SubscriptionTransitionData(
+        transition = new DefaultEffectiveSubscriptionEvent(new SubscriptionTransitionData(
                 UUID.randomUUID(),
                 subscriptionId,
                 bundle.getId(),
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 c6dc330..dedd0dc 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
@@ -28,9 +28,9 @@ import com.ning.billing.catalog.api.PlanPhase;
 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.EffectiveSubscriptionEvent;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.util.callcontext.CallContext;
 
@@ -106,7 +106,7 @@ public class MockSubscription implements Subscription {
     }
 
     @Override
-    public SubscriptionEvent getPendingTransition() {
+    public EffectiveSubscriptionEvent getPendingTransition() {
         throw new UnsupportedOperationException();
     }
 
@@ -121,7 +121,7 @@ public class MockSubscription implements Subscription {
     }
 
     @Override
-    public SubscriptionEvent getPreviousTransition() {
+    public EffectiveSubscriptionEvent getPreviousTransition() {
         return null;
     }
 
@@ -137,7 +137,7 @@ public class MockSubscription implements Subscription {
     }
 
     @Override
-    public List<SubscriptionEvent> getBillingTransitions() {
+    public List<EffectiveSubscriptionEvent> getBillingTransitions() {
         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 0b3287e..d43e0dc 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
@@ -41,7 +41,7 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.user.DefaultSubscriptionEvent;
+import com.ning.billing.entitlement.api.user.DefaultEffectiveSubscriptionEvent;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.events.EntitlementEvent;
@@ -98,7 +98,7 @@ public class TestAnalyticsListener extends AnalyticsTestSuite {
         final DateTime requestedTransitionTime = effectiveTransitionTime;
         final SubscriptionTransitionData firstTransition = createFirstSubscriptionTransition(requestedTransitionTime, effectiveTransitionTime);
         final BusinessSubscriptionTransition firstBST = createExpectedFirstBST(firstTransition.getTotalOrdering(), requestedTransitionTime, effectiveTransitionTime);
-        listener.handleSubscriptionTransitionChange(new DefaultSubscriptionEvent(firstTransition, effectiveTransitionTime));
+        listener.handleSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(firstTransition, effectiveTransitionTime));
         Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).size(), 1);
         Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).get(0), firstBST);
 
@@ -107,7 +107,7 @@ public class TestAnalyticsListener extends AnalyticsTestSuite {
         final DateTime requestedCancelTransitionTime = effectiveCancelTransitionTime;
         final SubscriptionTransitionData cancelledSubscriptionTransition = createCancelSubscriptionTransition(requestedCancelTransitionTime, effectiveCancelTransitionTime, firstTransition.getNextState());
         final BusinessSubscriptionTransition cancelledBST = createExpectedCancelledBST(cancelledSubscriptionTransition.getTotalOrdering(), requestedCancelTransitionTime, effectiveCancelTransitionTime, firstBST.getNextSubscription());
-        listener.handleSubscriptionTransitionChange(new DefaultSubscriptionEvent(cancelledSubscriptionTransition, effectiveTransitionTime));
+        listener.handleSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(cancelledSubscriptionTransition, effectiveTransitionTime));
         Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).size(), 2);
         Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).get(1), cancelledBST);
 
@@ -116,7 +116,7 @@ public class TestAnalyticsListener extends AnalyticsTestSuite {
         final DateTime requestedRecreatedTransitionTime = effectiveRecreatedTransitionTime;
         final SubscriptionTransitionData recreatedSubscriptionTransition = createRecreatedSubscriptionTransition(requestedRecreatedTransitionTime, effectiveRecreatedTransitionTime, cancelledSubscriptionTransition.getNextState());
         final BusinessSubscriptionTransition recreatedBST = createExpectedRecreatedBST(recreatedSubscriptionTransition.getTotalOrdering(), requestedRecreatedTransitionTime, effectiveRecreatedTransitionTime, cancelledBST.getNextSubscription());
-        listener.handleSubscriptionTransitionChange(new DefaultSubscriptionEvent(recreatedSubscriptionTransition, effectiveTransitionTime));
+        listener.handleSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(recreatedSubscriptionTransition, effectiveTransitionTime));
         Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).size(), 3);
         Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).get(2), recreatedBST);
 
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java
index 531ab7b..75c3ebc 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java
@@ -33,10 +33,10 @@ import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
 import com.ning.billing.catalog.api.Catalog;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 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.SubscriptionEvent;
 
 public class TestBusinessSubscriptionTransitionRecorder extends AnalyticsTestSuite {
     @Test(groups = "fast")
@@ -82,17 +82,17 @@ public class TestBusinessSubscriptionTransitionRecorder extends AnalyticsTestSui
         final BusinessSubscriptionTransitionRecorder recorder = new BusinessSubscriptionTransitionRecorder(sqlDao, catalogService, entitlementApi, accountApi);
 
         // Create an new subscription event
-        final SubscriptionEvent event = Mockito.mock(SubscriptionEvent.class);
-        Mockito.when(event.getId()).thenReturn(UUID.randomUUID());
-        Mockito.when(event.getRequestedTransitionTime()).thenReturn(new DateTime(DateTimeZone.UTC));
-        Mockito.when(event.getNextPlan()).thenReturn(UUID.randomUUID().toString());
-        Mockito.when(event.getEffectiveTransitionTime()).thenReturn(new DateTime(DateTimeZone.UTC));
-        Mockito.when(event.getSubscriptionStartDate()).thenReturn(new DateTime(DateTimeZone.UTC));
-        recorder.subscriptionCreated(event);
+        final EffectiveSubscriptionEvent eventEffective = Mockito.mock(EffectiveSubscriptionEvent.class);
+        Mockito.when(eventEffective.getId()).thenReturn(UUID.randomUUID());
+        Mockito.when(eventEffective.getRequestedTransitionTime()).thenReturn(new DateTime(DateTimeZone.UTC));
+        Mockito.when(eventEffective.getNextPlan()).thenReturn(UUID.randomUUID().toString());
+        Mockito.when(eventEffective.getEffectiveTransitionTime()).thenReturn(new DateTime(DateTimeZone.UTC));
+        Mockito.when(eventEffective.getSubscriptionStartDate()).thenReturn(new DateTime(DateTimeZone.UTC));
+        recorder.subscriptionCreated(eventEffective);
 
         Assert.assertEquals(sqlDao.getTransitions(externalKey.toString()).size(), 2);
         final BusinessSubscriptionTransition transition = sqlDao.getTransitions(externalKey.toString()).get(1);
-        Assert.assertEquals(transition.getTotalOrdering(), (long) event.getTotalOrdering());
+        Assert.assertEquals(transition.getTotalOrdering(), (long) eventEffective.getTotalOrdering());
         Assert.assertEquals(transition.getAccountKey(), externalKey.toString());
         // Make sure all the prev_ columns are null
         Assert.assertNull(transition.getPreviousSubscription());
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/EffectiveSubscriptionEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EffectiveSubscriptionEvent.java
new file mode 100644
index 0000000..84b03b4
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/EffectiveSubscriptionEvent.java
@@ -0,0 +1,20 @@
+/*
+ * 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;
+
+public interface EffectiveSubscriptionEvent extends SubscriptionEvent {
+}
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/RequestedSubscriptionEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/user/RequestedSubscriptionEvent.java
new file mode 100644
index 0000000..8baaf5b
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/RequestedSubscriptionEvent.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010-2012 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;
+
+public interface RequestedSubscriptionEvent extends SubscriptionEvent {
+}
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 e6f024c..ac17237 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
@@ -71,9 +71,9 @@ public interface Subscription extends Entity, Blockable {
 
     public ProductCategory getCategory();
 
-    public SubscriptionEvent getPendingTransition();
+    public EffectiveSubscriptionEvent getPendingTransition();
 
-    public SubscriptionEvent getPreviousTransition();
+    public EffectiveSubscriptionEvent getPreviousTransition();
 
-    public List<SubscriptionEvent> getBillingTransitions();
+    public List<EffectiveSubscriptionEvent> getBillingTransitions();
 }
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 61c76ee..479dbf5 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
@@ -18,20 +18,14 @@ package com.ning.billing.entitlement.api.user;
 
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-
 import com.ning.billing.junction.api.Blockable;
 import com.ning.billing.overdue.OverdueState;
 import com.ning.billing.util.entity.Entity;
 
 public interface SubscriptionBundle extends Blockable, Entity {
-
     public UUID getAccountId();
 
-    public DateTime getStartDate();
-
     public String getKey();
 
     public OverdueState<SubscriptionBundle> getOverdueState();
-
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvent.java
index 6d22268..f5a345d 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvent.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2012 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
@@ -25,7 +25,6 @@ import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.util.bus.BusEvent;
 
 public interface SubscriptionEvent extends BusEvent {
-
     UUID getId();
 
     SubscriptionTransitionType getTransitionType();
@@ -59,5 +58,4 @@ public interface SubscriptionEvent extends BusEvent {
     Integer getRemainingEventsForUserOperation();
 
     Long getTotalOrdering();
-
 }
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
index f491beb..19f1b65 100644
--- a/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestWaiter.java
+++ b/api/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestWaiter.java
@@ -20,7 +20,7 @@ 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.SubscriptionEvent;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.invoice.api.EmptyInvoiceEvent;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.payment.api.PaymentErrorEvent;
@@ -35,7 +35,7 @@ public interface CompletionUserRequestWaiter {
 
     public void onAccountChange(final AccountChangeEvent curEvent);
 
-    public void onSubscriptionTransition(final SubscriptionEvent curEvent);
+    public void onSubscriptionTransition(final EffectiveSubscriptionEvent curEventEffective);
 
     public void onInvoiceCreation(final InvoiceCreationEvent curEvent);
 
diff --git a/catalog/src/main/java/com/ning/billing/catalog/io/VersionedCatalogLoader.java b/catalog/src/main/java/com/ning/billing/catalog/io/VersionedCatalogLoader.java
index 95f5590..4bc57e3 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/io/VersionedCatalogLoader.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/io/VersionedCatalogLoader.java
@@ -22,6 +22,7 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 
+import com.google.common.io.Resources;
 import com.google.inject.Inject;
 import com.ning.billing.catalog.StandaloneCatalog;
 import com.ning.billing.catalog.VersionedCatalog;
@@ -48,10 +49,23 @@ public class VersionedCatalogLoader implements ICatalogLoader {
         try {
             List<URI> xmlURIs = null;
 
-            if (uriString.endsWith(XML_EXTENSION)) { //assume its an xml file
+            if (uriString.endsWith(XML_EXTENSION)) { // Assume its an xml file
                 xmlURIs = new ArrayList<URI>();
-                xmlURIs.add(new URI(uriString));
-            } else { //assume its a directory
+                URI uri = new URI(uriString);
+
+                // Try to expand the full path, if possible
+                final String schemeSpecificPart = uri.getSchemeSpecificPart();
+                if (schemeSpecificPart != null) {
+                    final String[] split = schemeSpecificPart.split("/");
+                    final String fileName = split[split.length - 1];
+                    try {
+                        uri = new URI(Resources.getResource(fileName).toExternalForm());
+                    } catch (IllegalArgumentException ignored) {
+                    }
+                }
+
+                xmlURIs.add(uri);
+            } else { // Assume its a directory
                 final String directoryContents = UriAccessor.accessUriAsString(uriString);
                 xmlURIs = findXmlReferences(directoryContents, new URL(uriString));
             }
@@ -61,6 +75,7 @@ public class VersionedCatalogLoader implements ICatalogLoader {
                 final StandaloneCatalog catalog = XMLLoader.getObjectFromUri(u, StandaloneCatalog.class);
                 result.add(catalog);
             }
+
             return result;
         } catch (Exception e) {
             throw new ServiceException("Problem encountered loading catalog", e);
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 9c5d3d2..cc6f0db 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -87,6 +87,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>
             <scope>test</scope>
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 d31452d..3593fea 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
@@ -16,6 +16,7 @@
 
 package com.ning.billing.entitlement.alignment;
 
+import javax.annotation.Nullable;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -43,11 +44,10 @@ import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.DefaultClock;
 
 /**
- * PlanAligner offers specific APIs to return the correct {@code TimedPhase} when creating, changing Plan or to compute next Phase on current Plan.
- * <p/>
+ * PlanAligner offers specific APIs to return the correct {@code TimedPhase} when creating, changing Plan or to compute
+ * next Phase on current Plan.
  */
 public class PlanAligner {
-
     private final CatalogService catalogService;
 
     @Inject
@@ -62,22 +62,29 @@ public class PlanAligner {
 
     /**
      * Returns the current and next phase for the subscription in creation
-     * <p/>
      *
-     * @param subscription  the subscription in creation
+     * @param subscription  the subscription in creation (only the start date and the bundle start date are looked at)
      * @param plan          the current Plan
      * @param initialPhase  the initialPhase on which we should create that subscription. can be null
      * @param priceList     the priceList
-     * @param effectiveDate the effective creation date
-     * @return
-     * @throws CatalogApiException
-     * @throws EntitlementUserApiException
+     * @param requestedDate the requested date (only used to load the catalog)
+     * @param effectiveDate the effective creation date (driven by the catalog policy, i.e. when the creation occurs)
+     * @return the current and next phases
+     * @throws CatalogApiException         for catalog errors
+     * @throws EntitlementUserApiException for entitlement errors
      */
     public TimedPhase[] getCurrentAndNextTimedPhaseOnCreate(final SubscriptionData subscription,
-                                                            final Plan plan, final PhaseType initialPhase, final String priceList, final DateTime requestedDate, final DateTime effectiveDate)
-            throws CatalogApiException, EntitlementUserApiException {
+                                                            final Plan plan,
+                                                            final PhaseType initialPhase,
+                                                            final String priceList,
+                                                            final DateTime requestedDate,
+                                                            final DateTime effectiveDate) throws CatalogApiException, EntitlementUserApiException {
         final List<TimedPhase> timedPhases = getTimedPhaseOnCreate(subscription.getStartDate(),
-                                                             subscription.getBundleStartDate(), plan, initialPhase, priceList, requestedDate);
+                                                                   subscription.getBundleStartDate(),
+                                                                   plan,
+                                                                   initialPhase,
+                                                                   priceList,
+                                                                   requestedDate);
         final TimedPhase[] result = new TimedPhase[2];
         result[0] = getTimedPhase(timedPhases, effectiveDate, WhichPhase.CURRENT);
         result[1] = getTimedPhase(timedPhases, effectiveDate, WhichPhase.NEXT);
@@ -86,52 +93,56 @@ public class PlanAligner {
 
     /**
      * Returns current Phase for that Plan change
-     * <p/>
      *
-     * @param subscription  the subscription in creation
+     * @param subscription  the subscription in change (only start date, bundle start date, current phase, plan and pricelist
+     *                      are looked at)
      * @param plan          the current Plan
      * @param priceList     the priceList on which we should change that subscription.
-     * @param effectiveDate the effective change date
-     * @return
-     * @throws CatalogApiException
-     * @throws EntitlementUserApiException
+     * @param requestedDate the requested date
+     * @param effectiveDate the effective change date (driven by the catalog policy, i.e. when the change occurs)
+     * @return the current phase
+     * @throws CatalogApiException         for catalog errors
+     * @throws EntitlementUserApiException for entitlement errors
      */
     public TimedPhase getCurrentTimedPhaseOnChange(final SubscriptionData subscription,
-                                                   final Plan plan, final String priceList, final DateTime requestedDate, final DateTime effectiveDate)
-            throws CatalogApiException, EntitlementUserApiException {
+                                                   final Plan plan,
+                                                   final String priceList,
+                                                   final DateTime requestedDate,
+                                                   final DateTime effectiveDate) throws CatalogApiException, EntitlementUserApiException {
         return getTimedPhaseOnChange(subscription, plan, priceList, requestedDate, effectiveDate, WhichPhase.CURRENT);
     }
 
     /**
      * Returns next Phase for that Plan change
-     * <p/>
      *
-     * @param subscription  the subscription in creation
+     * @param subscription  the subscription in change (only start date, bundle start date, current phase, plan and pricelist
+     *                      are looked at)
      * @param plan          the current Plan
      * @param priceList     the priceList on which we should change that subscription.
-     * @param effectiveDate the effective change date
-     * @return
-     * @throws CatalogApiException
-     * @throws EntitlementUserApiException
+     * @param requestedDate the requested date
+     * @param effectiveDate the effective change date (driven by the catalog policy, i.e. when the change occurs)
+     * @return the next phase
+     * @throws CatalogApiException         for catalog errors
+     * @throws EntitlementUserApiException for entitlement errors
      */
     public TimedPhase getNextTimedPhaseOnChange(final SubscriptionData subscription,
-                                                final Plan plan, final String priceList, final DateTime requestedDate, final DateTime effectiveDate)
-            throws CatalogApiException, EntitlementUserApiException {
+                                                final Plan plan,
+                                                final String priceList,
+                                                final DateTime requestedDate,
+                                                final DateTime effectiveDate) throws CatalogApiException, EntitlementUserApiException {
         return getTimedPhaseOnChange(subscription, plan, priceList, requestedDate, effectiveDate, WhichPhase.NEXT);
     }
 
-
     /**
      * Returns next Phase for that Subscription at a point in time
-     * <p/>
      *
      * @param subscription  the subscription for which we need to compute the next Phase event
+     * @param requestedDate the requested date
      * @param effectiveDate the date at which we look to compute that event. effective needs to be after last Plan change or initial Plan
-     * @return The PhaseEvent at the correct point in time
+     * @return the next phase
      */
     public TimedPhase getNextTimedPhase(final SubscriptionData subscription, final DateTime requestedDate, final DateTime effectiveDate) {
         try {
-
             final SubscriptionTransitionData 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",
@@ -139,18 +150,18 @@ public class PlanAligner {
             }
 
             switch (lastPlanTransition.getTransitionType()) {
-                // If we never had any Plan change, borrow the logics for createPlan alignment
+                // If we never had any Plan change, borrow the logic for createPlan alignment
                 case MIGRATE_ENTITLEMENT:
                 case CREATE:
                 case RE_CREATE:
                     final List<TimedPhase> timedPhases = getTimedPhaseOnCreate(subscription.getStartDate(),
-                                                                         subscription.getBundleStartDate(),
-                                                                         lastPlanTransition.getNextPlan(),
-                                                                         lastPlanTransition.getNextPhase().getPhaseType(),
-                                                                         lastPlanTransition.getNextPriceList().getName(),
-                                                                         requestedDate);
+                                                                               subscription.getBundleStartDate(),
+                                                                               lastPlanTransition.getNextPlan(),
+                                                                               lastPlanTransition.getNextPhase().getPhaseType(),
+                                                                               lastPlanTransition.getNextPriceList().getName(),
+                                                                               requestedDate);
                     return getTimedPhase(timedPhases, effectiveDate, WhichPhase.NEXT);
-                // If we went through Plan changes, borrow the logics for changePlan alignement
+                // If we went through Plan changes, borrow the logic for changePlan alignment
                 case CHANGE:
                     return getTimedPhaseOnChange(subscription.getStartDate(),
                                                  subscription.getBundleStartDate(),
@@ -163,7 +174,7 @@ public class PlanAligner {
                                                  effectiveDate,
                                                  WhichPhase.NEXT);
                 default:
-                    throw new EntitlementError(String.format("Unexpectd initial transition %s for current plan %s on subscription %s",
+                    throw new EntitlementError(String.format("Unexpected initial transition %s for current plan %s on subscription %s",
                                                              lastPlanTransition.getTransitionType(), subscription.getCurrentPlan(), subscription.getId()));
             }
         } catch (Exception /* EntitlementUserApiException, CatalogApiException */ e) {
@@ -171,22 +182,23 @@ public class PlanAligner {
         }
     }
 
-
     private List<TimedPhase> getTimedPhaseOnCreate(final DateTime subscriptionStartDate,
                                                    final DateTime bundleStartDate,
-                                                   final Plan plan, final PhaseType initialPhase, final String priceList, final DateTime requestedDate)
+                                                   final Plan plan,
+                                                   final PhaseType initialPhase,
+                                                   final String priceList,
+                                                   final DateTime requestedDate)
             throws CatalogApiException, EntitlementUserApiException {
-
         final Catalog catalog = catalogService.getFullCatalog();
 
         final PlanSpecifier planSpecifier = new PlanSpecifier(plan.getProduct().getName(),
-                                                        plan.getProduct().getCategory(),
-                                                        plan.getBillingPeriod(),
-                                                        priceList);
+                                                              plan.getProduct().getCategory(),
+                                                              plan.getBillingPeriod(),
+                                                              priceList);
 
-        DateTime planStartDate = null;
-        final PlanAlignmentCreate alignement = catalog.planCreateAlignment(planSpecifier, requestedDate);
-        switch (alignement) {
+        final DateTime planStartDate;
+        final PlanAlignmentCreate alignment = catalog.planCreateAlignment(planSpecifier, requestedDate);
+        switch (alignment) {
             case START_OF_SUBSCRIPTION:
                 planStartDate = subscriptionStartDate;
                 break;
@@ -194,14 +206,18 @@ public class PlanAligner {
                 planStartDate = bundleStartDate;
                 break;
             default:
-                throw new EntitlementError(String.format("Unknwon PlanAlignmentCreate %s", alignement));
+                throw new EntitlementError(String.format("Unknown PlanAlignmentCreate %s", alignment));
         }
+
         return getPhaseAlignments(plan, initialPhase, planStartDate);
     }
 
     private TimedPhase getTimedPhaseOnChange(final SubscriptionData subscription,
-                                             final Plan nextPlan, final String nextPriceList, final DateTime requestedDate, final DateTime effectiveDate, final WhichPhase which)
-            throws CatalogApiException, EntitlementUserApiException {
+                                             final Plan nextPlan,
+                                             final String nextPriceList,
+                                             final DateTime requestedDate,
+                                             final DateTime effectiveDate,
+                                             final WhichPhase which) throws CatalogApiException, EntitlementUserApiException {
         return getTimedPhaseOnChange(subscription.getStartDate(),
                                      subscription.getBundleStartDate(),
                                      subscription.getCurrentPhase(),
@@ -214,29 +230,30 @@ public class PlanAligner {
                                      which);
     }
 
-
     private TimedPhase getTimedPhaseOnChange(final DateTime subscriptionStartDate,
                                              final DateTime bundleStartDate,
                                              final PlanPhase currentPhase,
                                              final Plan currentPlan,
                                              final String currentPriceList,
-                                             final Plan nextPlan, final String priceList, final DateTime requestedDate, final DateTime effectiveDate, final WhichPhase which)
-            throws CatalogApiException, EntitlementUserApiException {
-
+                                             final Plan nextPlan,
+                                             final String priceList,
+                                             final DateTime requestedDate,
+                                             final DateTime effectiveDate,
+                                             final WhichPhase which) throws CatalogApiException, EntitlementUserApiException {
         final Catalog catalog = catalogService.getFullCatalog();
         final ProductCategory currentCategory = currentPlan.getProduct().getCategory();
         final PlanPhaseSpecifier fromPlanPhaseSpecifier = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                                                                           currentCategory,
-                                                                           currentPlan.getBillingPeriod(),
-                                                                           currentPriceList,
-                                                                           currentPhase.getPhaseType());
+                                                                                 currentCategory,
+                                                                                 currentPlan.getBillingPeriod(),
+                                                                                 currentPriceList,
+                                                                                 currentPhase.getPhaseType());
 
         final PlanSpecifier toPlanSpecifier = new PlanSpecifier(nextPlan.getProduct().getName(),
-                                                          nextPlan.getProduct().getCategory(),
-                                                          nextPlan.getBillingPeriod(),
-                                                          priceList);
+                                                                nextPlan.getProduct().getCategory(),
+                                                                nextPlan.getBillingPeriod(),
+                                                                priceList);
 
-        DateTime planStartDate = null;
+        final DateTime planStartDate;
         final PlanAlignmentChange alignment = catalog.planChangeAlignment(fromPlanPhaseSpecifier, toPlanSpecifier, requestedDate);
         switch (alignment) {
             case START_OF_SUBSCRIPTION:
@@ -251,22 +268,21 @@ public class PlanAligner {
             case CHANGE_OF_PRICELIST:
                 throw new EntitlementError(String.format("Not implemented yet %s", alignment));
             default:
-                throw new EntitlementError(String.format("Unknwon PlanAlignmentChange %s", alignment));
+                throw new EntitlementError(String.format("Unknown PlanAlignmentChange %s", alignment));
         }
+
         final List<TimedPhase> timedPhases = getPhaseAlignments(nextPlan, null, planStartDate);
         return getTimedPhase(timedPhases, effectiveDate, which);
     }
 
-
-    private List<TimedPhase> getPhaseAlignments(final Plan plan, final PhaseType initialPhase, final DateTime initialPhaseStartDate)
-            throws EntitlementUserApiException {
+    private List<TimedPhase> getPhaseAlignments(final Plan plan, @Nullable final PhaseType initialPhase, final DateTime initialPhaseStartDate) throws EntitlementUserApiException {
         if (plan == null) {
             return Collections.emptyList();
         }
 
         final List<TimedPhase> result = new LinkedList<TimedPhase>();
         DateTime curPhaseStart = (initialPhase == null) ? initialPhaseStartDate : null;
-        DateTime nextPhaseStart = null;
+        DateTime nextPhaseStart;
         for (final PlanPhase cur : plan.getAllPhases()) {
             // For create we can specify the phase so skip any phase until we reach initialPhase
             if (curPhaseStart == null) {
@@ -289,9 +305,11 @@ public class PlanAligner {
                 curPhaseStart = nextPhaseStart;
             }
         }
+
         if (initialPhase != null && curPhaseStart == null) {
             throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_BAD_PHASE, initialPhase);
         }
+
         return result;
     }
 
@@ -306,6 +324,7 @@ public class PlanAligner {
             }
             cur = phase;
         }
+
         switch (which) {
             case CURRENT:
                 return cur;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/TimedMigration.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/TimedMigration.java
index c692ca5..0c32b57 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/TimedMigration.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/TimedMigration.java
@@ -24,19 +24,15 @@ import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 
 public class TimedMigration {
-
     private final DateTime eventTime;
     private final EventType eventType;
     private final ApiEventType apiEventType;
-
     private final Plan plan;
     private final PlanPhase phase;
     private final String priceList;
 
-
-    public TimedMigration(final DateTime eventTime, final EventType eventType,
-                          final ApiEventType apiEventType, final Plan plan, final PlanPhase phase, final String priceList) {
-        super();
+    public TimedMigration(final DateTime eventTime, final EventType eventType, final ApiEventType apiEventType,
+                          final Plan plan, final PlanPhase phase, final String priceList) {
         this.eventTime = eventTime;
         this.eventType = eventType;
         this.apiEventType = apiEventType;
@@ -53,7 +49,6 @@ public class TimedMigration {
         return eventType;
     }
 
-
     public ApiEventType getApiEventType() {
         return apiEventType;
     }
@@ -69,4 +64,62 @@ public class TimedMigration {
     public String getPriceList() {
         return priceList;
     }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("TimedMigration");
+        sb.append("{apiEventType=").append(apiEventType);
+        sb.append(", eventTime=").append(eventTime);
+        sb.append(", eventType=").append(eventType);
+        sb.append(", plan=").append(plan);
+        sb.append(", phase=").append(phase);
+        sb.append(", priceList='").append(priceList).append('\'');
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final TimedMigration that = (TimedMigration) o;
+
+        if (apiEventType != that.apiEventType) {
+            return false;
+        }
+        if (eventTime != null ? !eventTime.equals(that.eventTime) : that.eventTime != null) {
+            return false;
+        }
+        if (eventType != that.eventType) {
+            return false;
+        }
+        if (phase != null ? !phase.equals(that.phase) : that.phase != null) {
+            return false;
+        }
+        if (plan != null ? !plan.equals(that.plan) : that.plan != null) {
+            return false;
+        }
+        if (priceList != null ? !priceList.equals(that.priceList) : that.priceList != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = eventTime != null ? eventTime.hashCode() : 0;
+        result = 31 * result + (eventType != null ? eventType.hashCode() : 0);
+        result = 31 * result + (apiEventType != null ? apiEventType.hashCode() : 0);
+        result = 31 * result + (plan != null ? plan.hashCode() : 0);
+        result = 31 * result + (phase != null ? phase.hashCode() : 0);
+        result = 31 * result + (priceList != null ? priceList.hashCode() : 0);
+        return result;
+    }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/TimedPhase.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/TimedPhase.java
index fb7bc1b..d79e940 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/TimedPhase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/TimedPhase.java
@@ -20,14 +20,11 @@ import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.PlanPhase;
 
-
 public final class TimedPhase {
-
     private final PlanPhase phase;
     private final DateTime startPhase;
 
     public TimedPhase(final PlanPhase phase, final DateTime startPhase) {
-        super();
         this.phase = phase;
         this.startPhase = startPhase;
     }
@@ -39,5 +36,43 @@ public final class TimedPhase {
     public DateTime getStartPhase() {
         return startPhase;
     }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("TimedPhase");
+        sb.append("{phase=").append(phase);
+        sb.append(", startPhase=").append(startPhase);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final TimedPhase phase1 = (TimedPhase) o;
+
+        if (phase != null ? !phase.equals(phase1.phase) : phase1.phase != null) {
+            return false;
+        }
+        if (startPhase != null ? !startPhase.equals(phase1.startPhase) : phase1.startPhase != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = phase != null ? phase.hashCode() : 0;
+        result = 31 * result + (startPhase != null ? startPhase.hashCode() : 0);
+        return result;
+    }
 }
 
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 e0f2860..fa79bda 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
@@ -78,7 +78,6 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
 
     private AccountMigrationData createAccountMigrationData(final EntitlementAccountMigration toBeMigrated, final CallContext context)
             throws EntitlementMigrationApiException {
-
         final UUID accountId = toBeMigrated.getAccountKey();
         final DateTime now = clock.getUTCNow();
 
@@ -89,7 +88,6 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
             final SubscriptionBundleData bundleData = new SubscriptionBundleData(curBundle.getBundleKey(), accountId, clock.getUTCNow());
             final List<SubscriptionMigrationData> bundleSubscriptionData = new LinkedList<AccountMigrationData.SubscriptionMigrationData>();
 
-
             final List<EntitlementSubscriptionMigration> sortedSubscriptions = Lists.newArrayList(curBundle.getSubscriptions());
             // Make sure we have first BASE or STANDALONE, then ADDON and for each category order by CED
             Collections.sort(sortedSubscriptions, new Comparator<EntitlementSubscriptionMigration>() {
@@ -99,10 +97,10 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
                     if (o1.getCategory().equals(o2.getCategory())) {
                         return o1.getSubscriptionCases()[0].getEffectiveDate().compareTo(o2.getSubscriptionCases()[0].getEffectiveDate());
                     } else {
-                    	if (!o1.getCategory().name().equalsIgnoreCase("ADD_ON")) {
+                        if (!o1.getCategory().name().equalsIgnoreCase("ADD_ON")) {
                             return -1;
                         } else if (o1.getCategory().name().equalsIgnoreCase("ADD_ON")) {
-                            return 1;                    
+                            return 1;
                         } else {
                             return 0;
                         }
@@ -127,24 +125,23 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
             final BundleMigrationData bundleMigrationData = new BundleMigrationData(bundleData, bundleSubscriptionData);
             accountBundleData.add(bundleMigrationData);
         }
-        final AccountMigrationData accountMigrationData = new AccountMigrationData(accountBundleData);
-        return accountMigrationData;
+
+        return new AccountMigrationData(accountBundleData);
     }
 
     private SubscriptionMigrationData createInitialSubscription(final UUID bundleId, final ProductCategory productCategory,
                                                                 final EntitlementSubscriptionMigrationCase[] input, final DateTime now, final DateTime ctd, final CallContext context)
             throws EntitlementMigrationApiException {
-
         final TimedMigration[] events = migrationAligner.getEventsMigration(input, now);
         final DateTime migrationStartDate = events[0].getEventTime();
         final List<EntitlementEvent> emptyEvents = Collections.emptyList();
         final SubscriptionData subscriptionData = factory.createSubscription(new SubscriptionBuilder()
-                                                                               .setId(UUID.randomUUID())
-                                                                               .setBundleId(bundleId)
-                                                                               .setCategory(productCategory)
-                                                                               .setBundleStartDate(migrationStartDate)
-                                                                               .setStartDate(migrationStartDate),
-                                                                       emptyEvents);
+                                                                                     .setId(UUID.randomUUID())
+                                                                                     .setBundleId(bundleId)
+                                                                                     .setCategory(productCategory)
+                                                                                     .setBundleStartDate(migrationStartDate)
+                                                                                     .setStartDate(migrationStartDate),
+                                                                             emptyEvents);
         return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, ctd, events, context));
     }
 
@@ -155,18 +152,16 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
         final DateTime migrationStartDate = events[0].getEventTime();
         final List<EntitlementEvent> emptyEvents = Collections.emptyList();
         final SubscriptionData subscriptionData = factory.createSubscription(new SubscriptionBuilder()
-                                                                               .setId(UUID.randomUUID())
-                                                                               .setBundleId(bundleId)
-                                                                               .setCategory(productCategory)
-                                                                               .setBundleStartDate(bundleStartDate)
-                                                                               .setStartDate(migrationStartDate),
-                                                                       emptyEvents);
+                                                                                     .setId(UUID.randomUUID())
+                                                                                     .setBundleId(bundleId)
+                                                                                     .setCategory(productCategory)
+                                                                                     .setBundleStartDate(bundleStartDate)
+                                                                                     .setStartDate(migrationStartDate),
+                                                                             emptyEvents);
         return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, ctd, events, context));
     }
 
     private List<EntitlementEvent> toEvents(final SubscriptionData subscriptionData, final DateTime now, final DateTime ctd, final TimedMigration[] migrationEvents, final CallContext context) {
-
-
         ApiEventMigrateEntitlement creationEvent = null;
         final List<EntitlementEvent> events = new ArrayList<EntitlementEvent>(migrationEvents.length);
         for (final TimedMigration cur : migrationEvents) {
@@ -213,9 +208,7 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
         }
         events.add(new ApiEventMigrateBilling(creationEvent, ctd));
         Collections.sort(events, new Comparator<EntitlementEvent>() {
-
             int compForApiType(final EntitlementEvent o1, final EntitlementEvent o2, final ApiEventType type) {
-
                 ApiEventType apiO1 = null;
                 if (o1.getType() == EventType.API_USER) {
                     apiO1 = ((ApiEvent) o1).getEventType();
@@ -224,9 +217,9 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
                 if (o2.getType() == EventType.API_USER) {
                     apiO2 = ((ApiEvent) o2).getEventType();
                 }
-                if (apiO1 != null && apiO1 == type) {
+                if (apiO1 != null && apiO1.equals(type)) {
                     return -1;
-                } else if (apiO2 != null && apiO2 == type) {
+                } else if (apiO2 != null && apiO2.equals(type)) {
                     return 1;
                 } else {
                     return 0;
@@ -246,6 +239,7 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
                 return comp;
             }
         });
+
         return events;
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
index 3162a75..368dbb5 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
@@ -13,12 +13,12 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.entitlement.api.timeline;
 
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
@@ -48,20 +48,17 @@ import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
 import com.ning.billing.util.callcontext.CallContext;
 
 public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
-
     private final EntitlementDao dao;
     private final SubscriptionFactory factory;
     private final RepairEntitlementLifecycleDao repairDao;
     private final CatalogService catalogService;
 
-
     private enum RepairType {
         BASE_REPAIR,
         ADD_ON_REPAIR,
         STANDALONE_REPAIR
     }
 
-
     @Inject
     public DefaultEntitlementTimelineApi(@Named(DefaultEntitlementModule.REPAIR_NAMED) final SubscriptionFactory factory, final CatalogService catalogService,
                                          @Named(DefaultEntitlementModule.REPAIR_NAMED) final RepairEntitlementLifecycleDao repairDao, final EntitlementDao dao) {
@@ -71,11 +68,8 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
         this.factory = factory;
     }
 
-
     @Override
-    public BundleTimeline getBundleRepair(final UUID bundleId)
-            throws EntitlementRepairException {
-
+    public BundleTimeline getBundleRepair(final UUID bundleId) throws EntitlementRepairException {
         try {
             final SubscriptionBundle bundle = dao.getSubscriptionBundleFromId(bundleId);
             if (bundle == null) {
@@ -93,19 +87,14 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
         }
     }
 
-
     @Override
-    public BundleTimeline repairBundle(final BundleTimeline input, final boolean dryRun, final CallContext context)
-            throws EntitlementRepairException {
-
+    public BundleTimeline repairBundle(final BundleTimeline input, final boolean dryRun, final CallContext context) throws EntitlementRepairException {
         try {
-
             final SubscriptionBundle bundle = dao.getSubscriptionBundleFromId(input.getBundleId());
             if (bundle == null) {
                 throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_UNKNOWN_BUNDLE, input.getBundleId());
             }
 
-
             // Subscriptions are ordered with BASE subscription first-- if exists
             final List<Subscription> subscriptions = dao.getSubscriptions(factory, input.getBundleId());
             if (subscriptions.size() == 0) {
@@ -127,8 +116,6 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
             final List<SubscriptionDataRepair> addOnSubscriptionInRepair = new LinkedList<SubscriptionDataRepair>();
             final List<SubscriptionDataRepair> inRepair = new LinkedList<SubscriptionDataRepair>();
             for (final Subscription cur : subscriptions) {
-
-                //
                 final SubscriptionTimeline curRepair = findAndCreateSubscriptionRepair(cur.getId(), input.getSubscriptions());
                 if (curRepair != null) {
                     final SubscriptionDataRepair curInputRepair = ((SubscriptionDataRepair) cur);
@@ -163,7 +150,6 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                         validateFirstNewEvent(curInputRepair, curRepair.getNewEvents().get(0), lastRemainingBPEventTime, lastRemainingEventTime);
                     }
 
-
                     final SubscriptionDataRepair curOutputRepair = createSubscriptionDataRepair(curInputRepair, newBundleStartDate, newSubscriptionStartDate, remaining);
                     repairDao.initializeRepair(curInputRepair.getId(), remaining);
                     inRepair.add(curOutputRepair);
@@ -191,7 +177,6 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                             addOnSubscriptionInRepair.add(curOutputRepair);
                         }
                     }
-
                     break;
                 case ADD_ON_REPAIR:
                     // We need to set the baseSubscription as it is useful to calculate addon validity
@@ -201,17 +186,14 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                 case STANDALONE_REPAIR:
                 default:
                     break;
-
             }
 
             validateBasePlanRecreate(isBasePlanRecreate, subscriptions, input.getSubscriptions());
             validateInputSubscriptionsKnown(subscriptions, input.getSubscriptions());
 
-
             final Collection<NewEvent> newEvents = createOrderedNewEventInput(input.getSubscriptions());
-            final Iterator<NewEvent> it = newEvents.iterator();
-            while (it.hasNext()) {
-                final DefaultNewEvent cur = (DefaultNewEvent) it.next();
+            for (final NewEvent newEvent : newEvents) {
+                final DefaultNewEvent cur = (DefaultNewEvent) newEvent;
                 final SubscriptionDataRepair curDataRepair = findSubscriptionDataRepair(cur.getSubscriptionId(), inRepair);
                 if (curDataRepair == null) {
                     throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_UNKNOWN_SUBSCRIPTION, cur.getSubscriptionId());
@@ -220,7 +202,6 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
             }
 
             if (dryRun) {
-
                 baseSubscriptionRepair.addFutureAddonCancellation(addOnSubscriptionInRepair, context);
 
                 final List<SubscriptionTimeline> repairs = createGetSubscriptionRepairList(subscriptions, convertDataRepair(inRepair));
@@ -236,7 +217,6 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
         }
     }
 
-
     private RepairType getRepairType(final Subscription firstSubscription, final boolean gotBaseSubscription) {
         if (firstSubscription.getCategory() == ProductCategory.BASE) {
             return gotBaseSubscription ? RepairType.BASE_REPAIR : RepairType.ADD_ON_REPAIR;
@@ -247,7 +227,6 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
 
     private void validateBasePlanRecreate(final boolean isBasePlanRecreate, final List<Subscription> subscriptions, final List<SubscriptionTimeline> input)
             throws EntitlementRepairException {
-
         if (!isBasePlanRecreate) {
             return;
         }
@@ -263,10 +242,8 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
         }
     }
 
-
     private void validateInputSubscriptionsKnown(final List<Subscription> subscriptions, final List<SubscriptionTimeline> input)
             throws EntitlementRepairException {
-
         for (final SubscriptionTimeline cur : input) {
             boolean found = false;
             for (final Subscription s : subscriptions) {
@@ -306,14 +283,13 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                 newEventSet.add(new DefaultNewEvent(cur.getId(), e.getPlanPhaseSpecifier(), e.getRequestedDate(), e.getSubscriptionTransitionType()));
             }
         }
+
         return newEventSet;
     }
 
-
     private List<EntitlementEvent> getRemainingEventsAndValidateDeletedEvents(final SubscriptionDataRepair data, final DateTime firstBPDeletedTime,
                                                                               final List<SubscriptionTimeline.DeletedEvent> deletedEvents)
             throws EntitlementRepairException {
-
         if (deletedEvents == null || deletedEvents.size() == 0) {
             return data.getEvents();
         }
@@ -343,13 +319,13 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                 result.add(cur);
             }
         }
+
         if (nbDeleted != deletedEvents.size()) {
             for (final SubscriptionTimeline.DeletedEvent d : deletedEvents) {
                 boolean found = false;
                 for (final SubscriptionTransitionData cur : data.getAllTransitions()) {
                     if (cur.getId().equals(d.getEventId())) {
                         found = true;
-                        continue;
                     }
                 }
                 if (!found) {
@@ -358,10 +334,10 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
             }
 
         }
+
         return result;
     }
 
-
     private String getViewId(final DateTime lastUpdateBundleDate, final List<Subscription> subscriptions) {
         final StringBuilder tmp = new StringBuilder();
         long lastOrderedId = -1;
@@ -371,6 +347,7 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
         tmp.append(lastOrderedId);
         tmp.append("-");
         tmp.append(lastUpdateBundleDate.toDate().getTime());
+
         return tmp.toString();
     }
 
@@ -396,7 +373,6 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                 return externalKey;
             }
         };
-
     }
 
     private List<SubscriptionTimeline> createGetSubscriptionRepairList(final List<Subscription> subscriptions, final List<SubscriptionTimeline> inRepair) throws CatalogApiException {
@@ -407,20 +383,22 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
             repairIds.add(cur.getId());
             result.add(cur);
         }
+
         for (final Subscription cur : subscriptions) {
             if (!repairIds.contains(cur.getId())) {
                 result.add(new DefaultSubscriptionTimeline((SubscriptionDataRepair) cur, catalogService.getFullCatalog()));
             }
         }
+
         return result;
     }
 
-
     private List<SubscriptionTimeline> convertDataRepair(final List<SubscriptionDataRepair> input) throws CatalogApiException {
         final List<SubscriptionTimeline> result = new LinkedList<SubscriptionTimeline>();
         for (final SubscriptionDataRepair cur : input) {
             result.add(new DefaultSubscriptionTimeline(cur, catalogService.getFullCatalog()));
         }
+
         return result;
     }
 
@@ -430,10 +408,10 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                 return cur;
             }
         }
+
         return null;
     }
 
-
     private SubscriptionDataRepair createSubscriptionDataRepair(final SubscriptionData curData, final DateTime newBundleStartDate, final DateTime newSubscriptionStartDate, final List<EntitlementEvent> initialEvents) {
         final SubscriptionBuilder builder = new SubscriptionBuilder(curData);
         builder.setActiveVersion(curData.getActiveVersion() + 1);
@@ -448,10 +426,9 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                 cur.setActiveVersion(builder.getActiveVersion());
             }
         }
-        final SubscriptionDataRepair result = (SubscriptionDataRepair) factory.createSubscription(builder, initialEvents);
-        return result;
-    }
 
+        return (SubscriptionDataRepair) factory.createSubscription(builder, initialEvents);
+    }
 
     private SubscriptionTimeline findAndCreateSubscriptionRepair(final UUID target, final List<SubscriptionTimeline> input) {
         for (final SubscriptionTimeline cur : input) {
@@ -459,6 +436,7 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
                 return new DefaultSubscriptionTimeline(cur);
             }
         }
+
         return null;
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java
index e09989d..f0cafe6 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.entitlement.api.timeline;
 
 import java.util.List;
@@ -31,7 +32,6 @@ import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
 import com.ning.billing.util.clock.Clock;
 
 public class RepairSubscriptionFactory extends DefaultSubscriptionFactory implements SubscriptionFactory {
-
     private final AddonUtils addonUtils;
     private final EntitlementDao repairDao;
 
@@ -47,8 +47,8 @@ public class RepairSubscriptionFactory extends DefaultSubscriptionFactory implem
     @Override
     public SubscriptionData createSubscription(final SubscriptionBuilder builder,
                                                final List<EntitlementEvent> events) {
-        final SubscriptionData subscription = new SubscriptionDataRepair(builder, events, apiService, repairDao, clock, addonUtils, catalogService);
-        subscription.rebuildTransitions(events, catalogService.getFullCatalog());
+        final SubscriptionData subscription = new SubscriptionDataRepair(builder, events, getApiService(), repairDao, getClock(), addonUtils, getCatalogService());
+        subscription.rebuildTransitions(events, getCatalogService().getFullCatalog());
         return subscription;
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
index 85c42a6..cdc6797 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.entitlement.api.timeline;
 
 import java.util.Collection;
@@ -47,7 +48,6 @@ import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 
 public class SubscriptionDataRepair extends SubscriptionData {
-
     private final AddonUtils addonUtils;
     private final Clock clock;
     private final EntitlementDao repairDao;
@@ -56,8 +56,7 @@ public class SubscriptionDataRepair extends SubscriptionData {
     private final List<EntitlementEvent> initialEvents;
 
     // Low level events are ONLY used for Repair APIs
-    protected List<EntitlementEvent> events;
-
+    private List<EntitlementEvent> events;
 
     public SubscriptionDataRepair(final SubscriptionBuilder builder, final List<EntitlementEvent> initialEvents, final SubscriptionApiService apiService,
                                   final EntitlementDao dao, final Clock clock, final AddonUtils addonUtils, final CatalogService catalogService) {
@@ -69,7 +68,6 @@ public class SubscriptionDataRepair extends SubscriptionData {
         this.initialEvents = initialEvents;
     }
 
-
     DateTime getLastUserEventEffectiveDate() {
         DateTime res = null;
         for (final EntitlementEvent cur : events) {
@@ -116,10 +114,9 @@ public class SubscriptionDataRepair extends SubscriptionData {
         }
     }
 
-
     public void addFutureAddonCancellation(final List<SubscriptionDataRepair> addOnSubscriptionInRepair, final CallContext context) {
 
-        if (category != ProductCategory.BASE) {
+        if (getCategory() != ProductCategory.BASE) {
             return;
         }
 
@@ -136,7 +133,7 @@ public class SubscriptionDataRepair extends SubscriptionData {
     private void trickleDownBPEffectForAddon(final List<SubscriptionDataRepair> addOnSubscriptionInRepair, final DateTime effectiveDate, final CallContext context)
             throws EntitlementUserApiException {
 
-        if (category != ProductCategory.BASE) {
+        if (getCategory() != ProductCategory.BASE) {
             return;
         }
 
@@ -145,7 +142,6 @@ public class SubscriptionDataRepair extends SubscriptionData {
         addAddonCancellationIfRequired(addOnSubscriptionInRepair, baseProduct, effectiveDate, context);
     }
 
-
     private void addAddonCancellationIfRequired(final List<SubscriptionDataRepair> addOnSubscriptionInRepair, final Product baseProduct, final DateTime effectiveDate, final CallContext context) {
 
         final DateTime now = clock.getUTCNow();
@@ -162,13 +158,13 @@ public class SubscriptionDataRepair extends SubscriptionData {
                     !addonUtils.isAddonAvailable(baseProduct, addonCurrentPlan)) {
 
                 final EntitlementEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
-                                                                          .setSubscriptionId(cur.getId())
-                                                                          .setActiveVersion(cur.getActiveVersion())
-                                                                          .setProcessedDate(now)
-                                                                          .setEffectiveDate(effectiveDate)
-                                                                          .setRequestedDate(now)
-                                                                          .setUserToken(context.getUserToken())
-                                                                          .setFromDisk(true));
+                                                                                .setSubscriptionId(cur.getId())
+                                                                                .setActiveVersion(cur.getActiveVersion())
+                                                                                .setProcessedDate(now)
+                                                                                .setEffectiveDate(effectiveDate)
+                                                                                .setRequestedDate(now)
+                                                                                .setUserToken(context.getUserToken())
+                                                                                .setFromDisk(true));
                 repairDao.cancelSubscription(cur.getId(), cancelEvent, context, 0);
                 cur.rebuildTransitions(repairDao.getEventsForSubscription(cur.getId()), catalogService.getFullCatalog());
             }
@@ -177,7 +173,7 @@ public class SubscriptionDataRepair extends SubscriptionData {
 
     private void checkAddonRights(final SubscriptionDataRepair baseSubscription)
             throws EntitlementUserApiException, CatalogApiException {
-        if (category == ProductCategory.ADD_ON) {
+        if (getCategory() == ProductCategory.ADD_ON) {
             addonUtils.checkAddonCreationRights(baseSubscription, getCurrentPlan());
         }
     }
@@ -195,14 +191,12 @@ public class SubscriptionDataRepair extends SubscriptionData {
         return initialEvents;
     }
 
-
     public Collection<EntitlementEvent> getNewEvents() {
-        final Collection<EntitlementEvent> newEvents = Collections2.filter(events, new Predicate<EntitlementEvent>() {
+        return Collections2.filter(events, new Predicate<EntitlementEvent>() {
             @Override
             public boolean apply(final EntitlementEvent input) {
                 return !initialEvents.contains(input);
             }
         });
-        return newEvents;
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEffectiveSubscriptionEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEffectiveSubscriptionEvent.java
new file mode 100644
index 0000000..f8d66af
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEffectiveSubscriptionEvent.java
@@ -0,0 +1,55 @@
+/*
+ * 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 java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ning.billing.entitlement.api.SubscriptionTransitionType;
+
+public class DefaultEffectiveSubscriptionEvent extends DefaultSubscriptionEvent implements EffectiveSubscriptionEvent {
+    public DefaultEffectiveSubscriptionEvent(final SubscriptionTransitionData in, final DateTime startDate) {
+        super(in, startDate);
+    }
+
+    @JsonCreator
+    public DefaultEffectiveSubscriptionEvent(@JsonProperty("eventId") final UUID eventId,
+                                             @JsonProperty("subscriptionId") final UUID subscriptionId,
+                                             @JsonProperty("bundleId") final UUID bundleId,
+                                             @JsonProperty("requestedTransitionTime") final DateTime requestedTransitionTime,
+                                             @JsonProperty("effectiveTransitionTime") final DateTime effectiveTransitionTime,
+                                             @JsonProperty("previousState") final Subscription.SubscriptionState previousState,
+                                             @JsonProperty("previousPlan") final String previousPlan,
+                                             @JsonProperty("previousPhase") final String previousPhase,
+                                             @JsonProperty("previousPriceList") final String previousPriceList,
+                                             @JsonProperty("nextState") final Subscription.SubscriptionState nextState,
+                                             @JsonProperty("nextPlan") final String nextPlan,
+                                             @JsonProperty("nextPhase") final String nextPhase,
+                                             @JsonProperty("nextPriceList") final String nextPriceList,
+                                             @JsonProperty("totalOrdering") final Long totalOrdering,
+                                             @JsonProperty("userToken") final UUID userToken,
+                                             @JsonProperty("transitionType") final SubscriptionTransitionType transitionType,
+                                             @JsonProperty("remainingEventsForUserOperation") final Integer remainingEventsForUserOperation,
+                                             @JsonProperty("startDate") final DateTime startDate) {
+        super(eventId, subscriptionId, bundleId, requestedTransitionTime, effectiveTransitionTime, previousState, previousPlan,
+              previousPhase, previousPriceList, nextState, nextPlan, nextPhase, nextPriceList, totalOrdering, userToken,
+              transitionType, remainingEventsForUserOperation, startDate);
+    }
+}
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 2b26c87..ce96066 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
@@ -63,7 +63,6 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
         this.subscriptionFactory = subscriptionFactory;
     }
 
-
     @Override
     public SubscriptionBundle getBundleFromId(final UUID id) throws EntitlementUserApiException {
         final SubscriptionBundle result = dao.getSubscriptionBundleFromId(id);
@@ -115,7 +114,6 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
         return result;
     }
 
-
     public SubscriptionBundle createBundleForAccount(final UUID accountId, final String bundleName, final CallContext context)
             throws EntitlementUserApiException {
         final SubscriptionBundleData bundle = new SubscriptionBundleData(bundleName, accountId, clock.getUTCNow());
@@ -123,12 +121,12 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
     }
 
     @Override
-    public Subscription createSubscription(final UUID bundleId, final PlanPhaseSpecifier spec, DateTime requestedDate,
+    public Subscription createSubscription(final UUID bundleId, final PlanPhaseSpecifier spec, final DateTime requestedDateWithMs,
                                            final CallContext context) throws EntitlementUserApiException {
         try {
             final String realPriceList = (spec.getPriceListName() == null) ? PriceListSet.DEFAULT_PRICELIST_NAME : spec.getPriceListName();
             final DateTime now = clock.getUTCNow();
-            requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : now;
+            final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
             if (requestedDate.isAfter(now)) {
                 throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_REQUESTED_DATE, requestedDate.toString());
             }
@@ -185,21 +183,18 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
                                                              plan.getProduct().getCategory().toString()));
             }
 
-            final SubscriptionData subscription = apiService.createPlan(new SubscriptionBuilder()
-                                                                          .setId(UUID.randomUUID())
-                                                                          .setBundleId(bundleId)
-                                                                          .setCategory(plan.getProduct().getCategory())
-                                                                          .setBundleStartDate(bundleStartDate)
-                                                                          .setStartDate(effectiveDate),
-                                                                  plan, spec.getPhaseType(), realPriceList, requestedDate, effectiveDate, now, context);
-
-            return subscription;
+            return apiService.createPlan(new SubscriptionBuilder()
+                                                 .setId(UUID.randomUUID())
+                                                 .setBundleId(bundleId)
+                                                 .setCategory(plan.getProduct().getCategory())
+                                                 .setBundleStartDate(bundleStartDate)
+                                                 .setStartDate(effectiveDate),
+                                         plan, spec.getPhaseType(), realPriceList, requestedDate, effectiveDate, now, context);
         } catch (CatalogApiException e) {
             throw new EntitlementUserApiException(e);
         }
     }
 
-
     @Override
     public DateTime getNextBillingDate(final UUID accountId) {
         final List<SubscriptionBundle> bundles = getBundlesForAccount(accountId);
@@ -217,7 +212,6 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
         return result;
     }
 
-
     @Override
     public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(final UUID subscriptionId, final String baseProductName, final DateTime requestedDate)
             throws EntitlementUserApiException {
@@ -247,9 +241,10 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
                 reason = DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN;
             }
             final SubscriptionStatusDryRun status = new DefaultSubscriptionStatusDryRun(cur.getId(),
-                                                                                  cur.getCurrentPlan().getProduct().getName(), cur.getCurrentPhase().getPhaseType(),
-                                                                                  cur.getCurrentPlan().getBillingPeriod(),
-                                                                                  cur.getCurrentPriceList().getName(), reason);
+                                                                                        cur.getCurrentPlan().getProduct().getName(),
+                                                                                        cur.getCurrentPhase().getPhaseType(),
+                                                                                        cur.getCurrentPlan().getBillingPeriod(),
+                                                                                        cur.getCurrentPriceList().getName(), reason);
             result.add(status);
         }
         return result;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java
new file mode 100644
index 0000000..f03ba35
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010-2012 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 java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ning.billing.entitlement.api.SubscriptionTransitionType;
+
+public class DefaultRequestedSubscriptionEvent extends DefaultSubscriptionEvent implements RequestedSubscriptionEvent {
+    public DefaultRequestedSubscriptionEvent(final SubscriptionTransitionData in, final DateTime startDate) {
+        super(in, startDate);
+    }
+
+    @JsonCreator
+    public DefaultRequestedSubscriptionEvent(@JsonProperty("eventId") final UUID eventId,
+                                             @JsonProperty("subscriptionId") final UUID subscriptionId,
+                                             @JsonProperty("bundleId") final UUID bundleId,
+                                             @JsonProperty("requestedTransitionTime") final DateTime requestedTransitionTime,
+                                             @JsonProperty("effectiveTransitionTime") final DateTime effectiveTransitionTime,
+                                             @JsonProperty("previousState") final Subscription.SubscriptionState previousState,
+                                             @JsonProperty("previousPlan") final String previousPlan,
+                                             @JsonProperty("previousPhase") final String previousPhase,
+                                             @JsonProperty("previousPriceList") final String previousPriceList,
+                                             @JsonProperty("nextState") final Subscription.SubscriptionState nextState,
+                                             @JsonProperty("nextPlan") final String nextPlan,
+                                             @JsonProperty("nextPhase") final String nextPhase,
+                                             @JsonProperty("nextPriceList") final String nextPriceList,
+                                             @JsonProperty("totalOrdering") final Long totalOrdering,
+                                             @JsonProperty("userToken") final UUID userToken,
+                                             @JsonProperty("transitionType") final SubscriptionTransitionType transitionType,
+                                             @JsonProperty("remainingEventsForUserOperation") final Integer remainingEventsForUserOperation,
+                                             @JsonProperty("startDate") final DateTime startDate) {
+        super(eventId, subscriptionId, bundleId, requestedTransitionTime, effectiveTransitionTime, previousState, previousPlan,
+              previousPhase, previousPriceList, nextState, nextPlan, nextPhase, nextPriceList, totalOrdering, userToken,
+              transitionType, remainingEventsForUserOperation, startDate);
+    }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
index 327edb4..4469661 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
@@ -58,7 +58,6 @@ import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.DefaultClock;
 
 public class DefaultSubscriptionApiService implements SubscriptionApiService {
-
     private final Clock clock;
     private final EntitlementDao dao;
     private final CatalogService catalogService;
@@ -74,25 +73,22 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
 
     public SubscriptionData createPlan(final SubscriptionBuilder builder, final Plan plan, final PhaseType initialPhase,
                                        final String realPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
-                                       final CallContext context)
-            throws EntitlementUserApiException {
+                                       final CallContext context) throws EntitlementUserApiException {
         final SubscriptionData subscription = new SubscriptionData(builder, this, clock);
 
-
         createFromSubscription(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, false, context);
         return subscription;
     }
 
-
-    public boolean recreatePlan(final SubscriptionData subscription, final PlanPhaseSpecifier spec, DateTime requestedDate, final CallContext context)
+    public boolean recreatePlan(final SubscriptionData subscription, final PlanPhaseSpecifier spec, final DateTime requestedDateWithMs, final CallContext context)
             throws EntitlementUserApiException {
-
         final SubscriptionState currentState = subscription.getState();
         if (currentState != null && currentState != SubscriptionState.CANCELLED) {
             throw new EntitlementUserApiException(ErrorCode.ENT_RECREATE_BAD_STATE, subscription.getId(), currentState);
         }
+
         final DateTime now = clock.getUTCNow();
-        requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : now;
+        final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
         validateRequestedDate(subscription, now, requestedDate);
 
         try {
@@ -116,10 +112,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
 
     private void createFromSubscription(final SubscriptionData subscription, final Plan plan, final PhaseType initialPhase,
                                         final String realPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
-                                        final boolean reCreate, final CallContext context)
-            throws EntitlementUserApiException {
-
-
+                                        final boolean reCreate, final CallContext context) throws EntitlementUserApiException {
         try {
             final TimedPhase[] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate);
 
@@ -156,9 +149,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
         }
     }
 
-    public boolean cancel(final SubscriptionData subscription, DateTime requestedDate, final boolean eot, final CallContext context)
-            throws EntitlementUserApiException {
-
+    public boolean cancel(final SubscriptionData subscription, final DateTime requestedDateWithMs, final boolean eot, final CallContext context) throws EntitlementUserApiException {
         try {
             final SubscriptionState currentState = subscription.getState();
             if (currentState != SubscriptionState.ACTIVE) {
@@ -166,27 +157,27 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
             }
 
             final DateTime now = clock.getUTCNow();
-            requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : now;
+            final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
             validateRequestedDate(subscription, now, requestedDate);
 
             final Plan currentPlan = subscription.getCurrentPlan();
             final PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                                                                  currentPlan.getProduct().getCategory(),
-                                                                  subscription.getCurrentPlan().getBillingPeriod(),
-                                                                  subscription.getCurrentPriceList().getName(),
-                                                                  subscription.getCurrentPhase().getPhaseType());
+                                                                        currentPlan.getProduct().getCategory(),
+                                                                        subscription.getCurrentPlan().getBillingPeriod(),
+                                                                        subscription.getCurrentPriceList().getName(),
+                                                                        subscription.getCurrentPhase().getPhaseType());
 
             final ActionPolicy policy = catalogService.getFullCatalog().planCancelPolicy(planPhase, requestedDate);
             final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, requestedDate);
 
             final EntitlementEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
-                                                                      .setSubscriptionId(subscription.getId())
-                                                                      .setActiveVersion(subscription.getActiveVersion())
-                                                                      .setProcessedDate(now)
-                                                                      .setEffectiveDate(effectiveDate)
-                                                                      .setRequestedDate(requestedDate)
-                                                                      .setUserToken(context.getUserToken())
-                                                                      .setFromDisk(true));
+                                                                            .setSubscriptionId(subscription.getId())
+                                                                            .setActiveVersion(subscription.getActiveVersion())
+                                                                            .setProcessedDate(now)
+                                                                            .setEffectiveDate(effectiveDate)
+                                                                            .setRequestedDate(requestedDate)
+                                                                            .setUserToken(context.getUserToken())
+                                                                            .setFromDisk(true));
 
             dao.cancelSubscription(subscription.getId(), cancelEvent, context, 0);
             subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
@@ -196,23 +187,20 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
         }
     }
 
-
-    public boolean uncancel(final SubscriptionData subscription, final CallContext context)
-            throws EntitlementUserApiException {
-
+    public boolean uncancel(final SubscriptionData subscription, final CallContext context) throws EntitlementUserApiException {
         if (!subscription.isSubscriptionFutureCancelled()) {
             throw new EntitlementUserApiException(ErrorCode.ENT_UNCANCEL_BAD_STATE, subscription.getId().toString());
         }
 
         final DateTime now = clock.getUTCNow();
         final EntitlementEvent uncancelEvent = new ApiEventUncancel(new ApiEventBuilder()
-                                                                      .setSubscriptionId(subscription.getId())
-                                                                      .setActiveVersion(subscription.getActiveVersion())
-                                                                      .setProcessedDate(now)
-                                                                      .setRequestedDate(now)
-                                                                      .setEffectiveDate(now)
-                                                                      .setUserToken(context.getUserToken())
-                                                                      .setFromDisk(true));
+                                                                            .setSubscriptionId(subscription.getId())
+                                                                            .setActiveVersion(subscription.getActiveVersion())
+                                                                            .setProcessedDate(now)
+                                                                            .setRequestedDate(now)
+                                                                            .setEffectiveDate(now)
+                                                                            .setUserToken(context.getUserToken())
+                                                                            .setFromDisk(true));
 
         final List<EntitlementEvent> uncancelEvents = new ArrayList<EntitlementEvent>();
         uncancelEvents.add(uncancelEvent);
@@ -224,20 +212,18 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
         if (nextPhaseEvent != null) {
             uncancelEvents.add(nextPhaseEvent);
         }
+
         dao.uncancelSubscription(subscription.getId(), uncancelEvents, context);
         subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
+
         return true;
     }
 
     public boolean changePlan(final SubscriptionData subscription, final String productName, final BillingPeriod term,
-                              final String priceList, DateTime requestedDate, final CallContext context)
-
-            throws EntitlementUserApiException {
-
+                              final String priceList, final DateTime requestedDateWithMs, final CallContext context) throws EntitlementUserApiException {
         try {
-
             final DateTime now = clock.getUTCNow();
-            requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : now;
+            final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
             validateRequestedDate(subscription, now, requestedDate);
 
             final PriceList currentPriceList = subscription.getCurrentPriceList();
@@ -256,13 +242,13 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
                 final Product destProduct = catalogService.getFullCatalog().findProduct(productName, requestedDate);
                 final Plan currentPlan = subscription.getCurrentPlan();
                 final PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                                                                          currentPlan.getProduct().getCategory(),
-                                                                          currentPlan.getBillingPeriod(),
-                                                                          currentPriceList.getName(), subscription.getCurrentPhase().getPhaseType());
+                                                                                currentPlan.getProduct().getCategory(),
+                                                                                currentPlan.getBillingPeriod(),
+                                                                                currentPriceList.getName(), subscription.getCurrentPhase().getPhaseType());
                 final PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
-                                                              destProduct.getCategory(),
-                                                              term,
-                                                              priceList);
+                                                                    destProduct.getCategory(),
+                                                                    term,
+                                                                    priceList);
 
                 planChangeResult = catalogService.getFullCatalog().planChange(fromPlanPhase, toPlanPhase, requestedDate);
             } catch (CatalogApiException e) {
@@ -278,16 +264,16 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
             final TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(subscription, newPlan, newPriceList.getName(), requestedDate, effectiveDate);
 
             final EntitlementEvent changeEvent = new ApiEventChange(new ApiEventBuilder()
-                                                                      .setSubscriptionId(subscription.getId())
-                                                                      .setEventPlan(newPlan.getName())
-                                                                      .setEventPlanPhase(currentTimedPhase.getPhase().getName())
-                                                                      .setEventPriceList(newPriceList.getName())
-                                                                      .setActiveVersion(subscription.getActiveVersion())
-                                                                      .setProcessedDate(now)
-                                                                      .setEffectiveDate(effectiveDate)
-                                                                      .setRequestedDate(requestedDate)
-                                                                      .setUserToken(context.getUserToken())
-                                                                      .setFromDisk(true));
+                                                                            .setSubscriptionId(subscription.getId())
+                                                                            .setEventPlan(newPlan.getName())
+                                                                            .setEventPlanPhase(currentTimedPhase.getPhase().getName())
+                                                                            .setEventPriceList(newPriceList.getName())
+                                                                            .setActiveVersion(subscription.getActiveVersion())
+                                                                            .setProcessedDate(now)
+                                                                            .setEffectiveDate(effectiveDate)
+                                                                            .setRequestedDate(requestedDate)
+                                                                            .setUserToken(context.getUserToken())
+                                                                            .setFromDisk(true));
 
             final TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, newPriceList.getName(), requestedDate, effectiveDate);
             final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
@@ -314,12 +300,10 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
             throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_REQUESTED_FUTURE_DATE, requestedDate.toString());
         }
 
-        final SubscriptionEvent previousTransition = subscription.getPreviousTransition();
+        final EffectiveSubscriptionEvent previousTransition = subscription.getPreviousTransition();
         if (previousTransition != null && 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/DefaultSubscriptionEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionEvent.java
index f28ddb7..7c119cc 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionEvent.java
@@ -1,5 +1,5 @@
-/* 
- * Copyright 2010-2011 Ning, Inc.
+/*
+ * Copyright 2010-2012 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
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.entitlement.api.user;
 
 import java.util.UUID;
@@ -23,28 +24,25 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
-
-public class DefaultSubscriptionEvent implements SubscriptionEvent {
 
+public abstract class DefaultSubscriptionEvent implements SubscriptionEvent {
     private final Long totalOrdering;
     private final UUID subscriptionId;
     private final UUID bundleId;
     private final UUID eventId;
     private final DateTime requestedTransitionTime;
     private final DateTime effectiveTransitionTime;
-    private final SubscriptionState previousState;
+    private final Subscription.SubscriptionState previousState;
     private final String previousPriceList;
     private final String previousPlan;
     private final String previousPhase;
-    private final SubscriptionState nextState;
+    private final Subscription.SubscriptionState nextState;
     private final String nextPriceList;
     private final String nextPlan;
     private final String nextPhase;
     private final Integer remainingEventsForUserOperation;
     private final UUID userToken;
     private final SubscriptionTransitionType transitionType;
-
     private final DateTime startDate;
 
     public DefaultSubscriptionEvent(final SubscriptionTransitionData in, final DateTime startDate) {
@@ -74,11 +72,11 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
                                     @JsonProperty("bundleId") final UUID bundleId,
                                     @JsonProperty("requestedTransitionTime") final DateTime requestedTransitionTime,
                                     @JsonProperty("effectiveTransitionTime") final DateTime effectiveTransitionTime,
-                                    @JsonProperty("previousState") final SubscriptionState previousState,
+                                    @JsonProperty("previousState") final Subscription.SubscriptionState previousState,
                                     @JsonProperty("previousPlan") final String previousPlan,
                                     @JsonProperty("previousPhase") final String previousPhase,
                                     @JsonProperty("previousPriceList") final String previousPriceList,
-                                    @JsonProperty("nextState") final SubscriptionState nextState,
+                                    @JsonProperty("nextState") final Subscription.SubscriptionState nextState,
                                     @JsonProperty("nextPlan") final String nextPlan,
                                     @JsonProperty("nextPhase") final String nextPhase,
                                     @JsonProperty("nextPriceList") final String nextPriceList,
@@ -87,7 +85,6 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
                                     @JsonProperty("transitionType") final SubscriptionTransitionType transitionType,
                                     @JsonProperty("remainingEventsForUserOperation") final Integer remainingEventsForUserOperation,
                                     @JsonProperty("startDate") final DateTime startDate) {
-        super();
         this.eventId = eventId;
         this.subscriptionId = subscriptionId;
         this.bundleId = bundleId;
@@ -130,9 +127,8 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
         return bundleId;
     }
 
-
     @Override
-    public SubscriptionState getPreviousState() {
+    public Subscription.SubscriptionState getPreviousState() {
         return previousState;
     }
 
@@ -157,11 +153,10 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
     }
 
     @Override
-    public SubscriptionState getNextState() {
+    public Subscription.SubscriptionState getNextState() {
         return nextState;
     }
 
-
     @Override
     public String getPreviousPriceList() {
         return previousPriceList;
@@ -182,7 +177,6 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
         return remainingEventsForUserOperation;
     }
 
-
     @Override
     public DateTime getRequestedTransitionTime() {
         return requestedTransitionTime;
@@ -209,197 +203,121 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
         return startDate;
     }
 
-
     @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result
-                + ((bundleId == null) ? 0 : bundleId.hashCode());
-        result = prime
-                * result
-                + ((effectiveTransitionTime == null) ? 0
-                : effectiveTransitionTime.hashCode());
-        result = prime * result + ((eventId == null) ? 0 : eventId.hashCode());
-        result = prime * result
-                + ((nextPhase == null) ? 0 : nextPhase.hashCode());
-        result = prime * result
-                + ((nextPlan == null) ? 0 : nextPlan.hashCode());
-        result = prime * result
-                + ((nextPriceList == null) ? 0 : nextPriceList.hashCode());
-        result = prime * result
-                + ((nextState == null) ? 0 : nextState.hashCode());
-        result = prime * result
-                + ((previousPhase == null) ? 0 : previousPhase.hashCode());
-        result = prime * result
-                + ((previousPlan == null) ? 0 : previousPlan.hashCode());
-        result = prime
-                * result
-                + ((previousPriceList == null) ? 0 : previousPriceList
-                .hashCode());
-        result = prime * result
-                + ((previousState == null) ? 0 : previousState.hashCode());
-        result = prime
-                * result
-                + ((remainingEventsForUserOperation == null) ? 0
-                : remainingEventsForUserOperation.hashCode());
-        result = prime
-                * result
-                + ((requestedTransitionTime == null) ? 0
-                : requestedTransitionTime.hashCode());
-        result = prime * result
-                + ((subscriptionId == null) ? 0 : subscriptionId.hashCode());
-        result = prime * result
-                + ((totalOrdering == null) ? 0 : totalOrdering.hashCode());
-        result = prime * result
-                + ((transitionType == null) ? 0 : transitionType.hashCode());
-        result = prime * result
-                + ((userToken == null) ? 0 : userToken.hashCode());
-        return result;
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append("{bundleId=").append(bundleId);
+        sb.append(", totalOrdering=").append(totalOrdering);
+        sb.append(", subscriptionId=").append(subscriptionId);
+        sb.append(", eventId=").append(eventId);
+        sb.append(", requestedTransitionTime=").append(requestedTransitionTime);
+        sb.append(", effectiveTransitionTime=").append(effectiveTransitionTime);
+        sb.append(", previousState=").append(previousState);
+        sb.append(", previousPriceList='").append(previousPriceList).append('\'');
+        sb.append(", previousPlan='").append(previousPlan).append('\'');
+        sb.append(", previousPhase='").append(previousPhase).append('\'');
+        sb.append(", nextState=").append(nextState);
+        sb.append(", nextPriceList='").append(nextPriceList).append('\'');
+        sb.append(", nextPlan='").append(nextPlan).append('\'');
+        sb.append(", nextPhase='").append(nextPhase).append('\'');
+        sb.append(", remainingEventsForUserOperation=").append(remainingEventsForUserOperation);
+        sb.append(", userToken=").append(userToken);
+        sb.append(", transitionType=").append(transitionType);
+        sb.append(", startDate=").append(startDate);
+        sb.append('}');
+        return sb.toString();
     }
 
     @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
+    public boolean equals(final Object o) {
+        if (this == o) {
             return true;
         }
-        if (obj == null) {
+        if (o == null || getClass() != o.getClass()) {
             return false;
         }
-        if (getClass() != obj.getClass()) {
+
+        final DefaultSubscriptionEvent that = (DefaultSubscriptionEvent) o;
+
+        if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
             return false;
         }
-        final DefaultSubscriptionEvent other = (DefaultSubscriptionEvent) obj;
-        if (bundleId == null) {
-            if (other.bundleId != null) {
-                return false;
-            }
-        } else if (!bundleId.equals(other.bundleId)) {
+        if (effectiveTransitionTime != null ? effectiveTransitionTime.compareTo(that.effectiveTransitionTime) != 0 : that.effectiveTransitionTime != null) {
             return false;
         }
-        if (effectiveTransitionTime == null) {
-            if (other.effectiveTransitionTime != null) {
-                return false;
-            }
-        } else if (effectiveTransitionTime
-                .compareTo(other.effectiveTransitionTime) != 0) {
+        if (eventId != null ? !eventId.equals(that.eventId) : that.eventId != null) {
             return false;
         }
-        if (eventId == null) {
-            if (other.eventId != null) {
-                return false;
-            }
-        } else if (!eventId.equals(other.eventId)) {
+        if (nextPhase != null ? !nextPhase.equals(that.nextPhase) : that.nextPhase != null) {
             return false;
         }
-        if (nextPhase == null) {
-            if (other.nextPhase != null) {
-                return false;
-            }
-        } else if (!nextPhase.equals(other.nextPhase)) {
+        if (nextPlan != null ? !nextPlan.equals(that.nextPlan) : that.nextPlan != null) {
             return false;
         }
-        if (nextPlan == null) {
-            if (other.nextPlan != null) {
-                return false;
-            }
-        } else if (!nextPlan.equals(other.nextPlan)) {
+        if (nextPriceList != null ? !nextPriceList.equals(that.nextPriceList) : that.nextPriceList != null) {
             return false;
         }
-        if (nextPriceList == null) {
-            if (other.nextPriceList != null) {
-                return false;
-            }
-        } else if (!nextPriceList.equals(other.nextPriceList)) {
+        if (nextState != that.nextState) {
             return false;
         }
-        if (nextState != other.nextState) {
+        if (previousPhase != null ? !previousPhase.equals(that.previousPhase) : that.previousPhase != null) {
             return false;
         }
-        if (previousPhase == null) {
-            if (other.previousPhase != null) {
-                return false;
-            }
-        } else if (!previousPhase.equals(other.previousPhase)) {
+        if (previousPlan != null ? !previousPlan.equals(that.previousPlan) : that.previousPlan != null) {
             return false;
         }
-        if (previousPlan == null) {
-            if (other.previousPlan != null) {
-                return false;
-            }
-        } else if (!previousPlan.equals(other.previousPlan)) {
+        if (previousPriceList != null ? !previousPriceList.equals(that.previousPriceList) : that.previousPriceList != null) {
             return false;
         }
-        if (previousPriceList == null) {
-            if (other.previousPriceList != null) {
-                return false;
-            }
-        } else if (!previousPriceList.equals(other.previousPriceList)) {
+        if (previousState != that.previousState) {
             return false;
         }
-        if (previousState != other.previousState) {
+        if (remainingEventsForUserOperation != null ? !remainingEventsForUserOperation.equals(that.remainingEventsForUserOperation) : that.remainingEventsForUserOperation != null) {
             return false;
         }
-        if (remainingEventsForUserOperation == null) {
-            if (other.remainingEventsForUserOperation != null) {
-                return false;
-            }
-        } else if (!remainingEventsForUserOperation
-                .equals(other.remainingEventsForUserOperation)) {
+        if (requestedTransitionTime != null ? requestedTransitionTime.compareTo(that.requestedTransitionTime) != 0 : that.requestedTransitionTime != null) {
             return false;
         }
-        if (requestedTransitionTime == null) {
-            if (other.requestedTransitionTime != null) {
-                return false;
-            }
-        } else if (requestedTransitionTime
-                .compareTo(other.requestedTransitionTime) != 0) {
+        if (startDate != null ? startDate.compareTo(that.startDate) != 0 : that.startDate != null) {
             return false;
         }
-        if (subscriptionId == null) {
-            if (other.subscriptionId != null) {
-                return false;
-            }
-        } else if (!subscriptionId.equals(other.subscriptionId)) {
+        if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
             return false;
         }
-        if (totalOrdering == null) {
-            if (other.totalOrdering != null) {
-                return false;
-            }
-        } else if (!totalOrdering.equals(other.totalOrdering)) {
+        if (totalOrdering != null ? !totalOrdering.equals(that.totalOrdering) : that.totalOrdering != null) {
             return false;
         }
-        if (transitionType != other.transitionType) {
+        if (transitionType != that.transitionType) {
             return false;
         }
-        if (userToken == null) {
-            if (other.userToken != null) {
-                return false;
-            }
-        } else if (!userToken.equals(other.userToken)) {
+        if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
             return false;
         }
+
         return true;
     }
 
     @Override
-    public String toString() {
-        return "DefaultSubscriptionEvent [transitionType=" + transitionType
-                + ", effectiveTransitionTime=" + effectiveTransitionTime
-                + ", totalOrdering=" + totalOrdering
-                + ", subscriptionId=" + subscriptionId + ", bundleId="
-                + bundleId + ", eventId=" + eventId
-                + ", requestedTransitionTime=" + requestedTransitionTime
-                + ", previousState=" + previousState + ", previousPriceList="
-                + previousPriceList + ", previousPlan=" + previousPlan
-                + ", previousPhase=" + previousPhase + ", nextState="
-                + nextState + ", nextPriceList=" + nextPriceList
-                + ", nextPlan=" + nextPlan + ", nextPhase=" + nextPhase
-                + ", remainingEventsForUserOperation="
-                + remainingEventsForUserOperation + ", userToken=" + userToken
-                + ", startDate=" + startDate + "]";
-
+    public int hashCode() {
+        int result = totalOrdering != null ? totalOrdering.hashCode() : 0;
+        result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
+        result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
+        result = 31 * result + (eventId != null ? eventId.hashCode() : 0);
+        result = 31 * result + (requestedTransitionTime != null ? requestedTransitionTime.hashCode() : 0);
+        result = 31 * result + (effectiveTransitionTime != null ? effectiveTransitionTime.hashCode() : 0);
+        result = 31 * result + (previousState != null ? previousState.hashCode() : 0);
+        result = 31 * result + (previousPriceList != null ? previousPriceList.hashCode() : 0);
+        result = 31 * result + (previousPlan != null ? previousPlan.hashCode() : 0);
+        result = 31 * result + (previousPhase != null ? previousPhase.hashCode() : 0);
+        result = 31 * result + (nextState != null ? nextState.hashCode() : 0);
+        result = 31 * result + (nextPriceList != null ? nextPriceList.hashCode() : 0);
+        result = 31 * result + (nextPlan != null ? nextPlan.hashCode() : 0);
+        result = 31 * result + (nextPhase != null ? nextPhase.hashCode() : 0);
+        result = 31 * result + (remainingEventsForUserOperation != null ? remainingEventsForUserOperation.hashCode() : 0);
+        result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
+        result = 31 * result + (transitionType != null ? transitionType.hashCode() : 0);
+        result = 31 * result + (startDate != null ? startDate.hashCode() : 0);
+        return result;
     }
-
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
index bb2188f..8bd7471 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
@@ -32,10 +32,9 @@ import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.Clock;
 
 public class DefaultSubscriptionFactory implements SubscriptionFactory {
-
-    protected final SubscriptionApiService apiService;
-    protected final Clock clock;
-    protected final CatalogService catalogService;
+    private final SubscriptionApiService apiService;
+    private final Clock clock;
+    private final CatalogService catalogService;
 
     @Inject
     public DefaultSubscriptionFactory(final SubscriptionApiService apiService, final Clock clock, final CatalogService catalogService) {
@@ -44,7 +43,6 @@ public class DefaultSubscriptionFactory implements SubscriptionFactory {
         this.catalogService = catalogService;
     }
 
-
     public SubscriptionData createSubscription(final SubscriptionBuilder builder, final List<EntitlementEvent> events) {
         final SubscriptionData subscription = new SubscriptionData(builder, apiService, clock);
         if (events.size() > 0) {
@@ -53,9 +51,7 @@ public class DefaultSubscriptionFactory implements SubscriptionFactory {
         return subscription;
     }
 
-
     public static class SubscriptionBuilder {
-
         private UUID id;
         private UUID bundleId;
         private DateTime startDate;
@@ -80,7 +76,6 @@ public class DefaultSubscriptionFactory implements SubscriptionFactory {
             this.paidThroughDate = original.getPaidThroughDate();
         }
 
-
         public SubscriptionBuilder setId(final UUID id) {
             this.id = id;
             return this;
@@ -169,5 +164,15 @@ public class DefaultSubscriptionFactory implements SubscriptionFactory {
         }
     }
 
+    public SubscriptionApiService getApiService() {
+        return apiService;
+    }
+
+    public CatalogService getCatalogService() {
+        return catalogService;
+    }
 
+    public Clock getClock() {
+        return clock;
+    }
 }
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 be076ba..ede9ec0 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
@@ -16,6 +16,7 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import javax.annotation.Nullable;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
@@ -24,28 +25,24 @@ import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.overdue.OverdueState;
 
 public class SubscriptionBundleData implements SubscriptionBundle {
-
     private final UUID id;
     private final String key;
     private final UUID accountId;
-    private final DateTime startDate;
     private final DateTime lastSysTimeUpdate;
     private final OverdueState<SubscriptionBundle> overdueState;
 
     public SubscriptionBundleData(final String name, final UUID accountId, final DateTime startDate) {
-        this(UUID.randomUUID(), name, accountId, startDate, startDate);
+        this(UUID.randomUUID(), name, accountId, startDate);
     }
 
-    public SubscriptionBundleData(final UUID id, final String key, final UUID accountId, final DateTime startDate, final DateTime lastSysUpdate) {
-        this(id, key, accountId, startDate, lastSysUpdate, null);
+    public SubscriptionBundleData(final UUID id, final String key, final UUID accountId, final DateTime lastSysUpdate) {
+        this(id, key, accountId, lastSysUpdate, null);
     }
 
-    public SubscriptionBundleData(final UUID id, final String key, final UUID accountId, final DateTime startDate, final DateTime lastSysUpdate, final OverdueState<SubscriptionBundle> overdueState) {
-        super();
+    public SubscriptionBundleData(final UUID id, final String key, final UUID accountId, final DateTime lastSysUpdate, @Nullable final OverdueState<SubscriptionBundle> overdueState) {
         this.id = id;
         this.key = key;
         this.accountId = accountId;
-        this.startDate = startDate;
         this.lastSysTimeUpdate = lastSysUpdate;
         this.overdueState = overdueState;
     }
@@ -65,12 +62,6 @@ public class SubscriptionBundleData implements SubscriptionBundle {
         return accountId;
     }
 
-    // STEPH do we need it ? and should we return that and when is that populated/updated?
-    @Override
-    public DateTime getStartDate() {
-        return startDate;
-    }
-
     public DateTime getLastSysUpdateTime() {
         return lastSysTimeUpdate;
     }
@@ -84,4 +75,57 @@ public class SubscriptionBundleData implements SubscriptionBundle {
     public BlockingState getBlockingState() {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SubscriptionBundleData");
+        sb.append("{accountId=").append(accountId);
+        sb.append(", id=").append(id);
+        sb.append(", key='").append(key).append('\'');
+        sb.append(", lastSysTimeUpdate=").append(lastSysTimeUpdate);
+        sb.append(", overdueState=").append(overdueState);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final SubscriptionBundleData that = (SubscriptionBundleData) o;
+
+        if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
+            return false;
+        }
+        if (id != null ? !id.equals(that.id) : that.id != null) {
+            return false;
+        }
+        if (key != null ? !key.equals(that.key) : that.key != null) {
+            return false;
+        }
+        if (lastSysTimeUpdate != null ? !lastSysTimeUpdate.equals(that.lastSysTimeUpdate) : that.lastSysTimeUpdate != null) {
+            return false;
+        }
+        if (overdueState != null ? !overdueState.equals(that.overdueState) : that.overdueState != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = id != null ? id.hashCode() : 0;
+        result = 31 * result + (key != null ? key.hashCode() : 0);
+        result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
+        result = 31 * result + (lastSysTimeUpdate != null ? lastSysTimeUpdate.hashCode() : 0);
+        result = 31 * result + (overdueState != null ? overdueState.hashCode() : 0);
+        return result;
+    }
 }
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 e162011..409bc8d 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
@@ -54,35 +54,33 @@ import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.entity.EntityBase;
 
 public class SubscriptionData extends EntityBase implements Subscription {
-
     private static final Logger log = LoggerFactory.getLogger(SubscriptionData.class);
 
+    private final Clock clock;
+    private final SubscriptionApiService apiService;
 
-    protected final Clock clock;
-    protected final SubscriptionApiService apiService;
     //
     // Final subscription fields
     //
-    protected final UUID bundleId;
-    protected final DateTime startDate;
-    protected final DateTime bundleStartDate;
-    protected final ProductCategory category;
+    private final UUID bundleId;
+    private final DateTime startDate;
+    private final DateTime bundleStartDate;
+    private final ProductCategory category;
 
     //
     // Those can be modified through non User APIs, and a new Subscription
     // object would be created
     //
-    protected final long activeVersion;
-    protected final DateTime chargedThroughDate;
-    protected final DateTime paidThroughDate;
-
+    private final long activeVersion;
+    private final DateTime chargedThroughDate;
+    private final DateTime paidThroughDate;
 
     //
     // User APIs (create, change, cancel,...) will recompute those each time,
     // so the user holding that subscription object get the correct state when
     // the call completes
     //
-    protected LinkedList<SubscriptionTransitionData> transitions;
+    private LinkedList<SubscriptionTransitionData> transitions;
 
     // Transient object never returned at the API
     public SubscriptionData(final SubscriptionBuilder builder) {
@@ -140,7 +138,7 @@ public class SubscriptionData extends EntityBase implements Subscription {
 
     @Override
     public DateTime getEndDate() {
-        final SubscriptionEvent latestTransition = getPreviousTransition();
+        final EffectiveSubscriptionEvent latestTransition = getPreviousTransition();
         if (latestTransition.getNextState() == SubscriptionState.CANCELLED) {
             return latestTransition.getEffectiveTransitionTime();
         }
@@ -174,12 +172,12 @@ public class SubscriptionData extends EntityBase implements Subscription {
     }
 
     @Override
-    public SubscriptionEvent getPendingTransition() {
+    public EffectiveSubscriptionEvent getPendingTransition() {
         final SubscriptionTransitionData data = getPendingTransitionData();
         if (data == null) {
             return null;
         }
-        return new DefaultSubscriptionEvent(data, startDate);
+        return new DefaultEffectiveSubscriptionEvent(data, startDate);
     }
 
     @Override
@@ -198,12 +196,12 @@ public class SubscriptionData extends EntityBase implements Subscription {
     }
 
     @Override
-    public SubscriptionEvent getPreviousTransition() {
+    public EffectiveSubscriptionEvent getPreviousTransition() {
         final SubscriptionTransitionData data = getPreviousTransitionData();
         if (data == null) {
             return null;
         }
-        return new DefaultSubscriptionEvent(data, startDate);
+        return new DefaultEffectiveSubscriptionEvent(data, startDate);
     }
 
     protected SubscriptionTransitionData getPreviousTransitionData() {
@@ -266,30 +264,29 @@ public class SubscriptionData extends EntityBase implements Subscription {
         return true;
     }
 
-    public List<SubscriptionEvent> getBillingTransitions() {
+    public List<EffectiveSubscriptionEvent> getBillingTransitions() {
 
         if (transitions == null) {
             return Collections.emptyList();
         }
-        final List<SubscriptionEvent> result = new ArrayList<SubscriptionEvent>();
+        final List<EffectiveSubscriptionEvent> result = new ArrayList<EffectiveSubscriptionEvent>();
         final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(
                 clock, transitions, Order.ASC_FROM_PAST, Kind.BILLING,
                 Visibility.ALL, TimeLimit.ALL);
         while (it.hasNext()) {
-            result.add(new DefaultSubscriptionEvent(it.next(), startDate));
+            result.add(new DefaultEffectiveSubscriptionEvent(it.next(), startDate));
         }
         return result;
     }
 
-
-    public SubscriptionEvent getTransitionFromEvent(final EntitlementEvent event, final int seqId) {
+    public EffectiveSubscriptionEvent getTransitionFromEvent(final EntitlementEvent event, final int seqId) {
         if (transitions == null || event == null) {
             return null;
         }
         for (final SubscriptionTransitionData cur : transitions) {
             if (cur.getId().equals(event.getId())) {
                 final SubscriptionTransitionData withSeq = new SubscriptionTransitionData(cur, seqId);
-                return new DefaultSubscriptionEvent(withSeq, startDate);
+                return new DefaultEffectiveSubscriptionEvent(withSeq, startDate);
             }
         }
         return null;
@@ -306,20 +303,22 @@ public class SubscriptionData extends EntityBase implements Subscription {
         return activeVersion;
     }
 
-
     public List<SubscriptionTransitionData> getAllTransitions() {
         return transitions;
     }
 
     public SubscriptionTransitionData getInitialTransitionForCurrentPlan() {
         if (transitions == null) {
-            throw new EntitlementError(String.format(
-                    "No transitions for subscription %s", getId()));
+            throw new EntitlementError(String.format("No transitions for subscription %s", getId()));
         }
 
-        final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(
-                clock, transitions, Order.DESC_FROM_FUTURE, Kind.ENTITLEMENT,
-                Visibility.ALL, TimeLimit.PAST_OR_PRESENT_ONLY);
+        final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock,
+                                                                                             transitions,
+                                                                                             Order.DESC_FROM_FUTURE,
+                                                                                             Kind.ENTITLEMENT,
+                                                                                             Visibility.ALL,
+                                                                                             TimeLimit.PAST_OR_PRESENT_ONLY);
+
         while (it.hasNext()) {
             final SubscriptionTransitionData cur = it.next();
             if (cur.getTransitionType() == SubscriptionTransitionType.CREATE
@@ -329,9 +328,8 @@ public class SubscriptionData extends EntityBase implements Subscription {
                 return cur;
             }
         }
-        throw new EntitlementError(String.format(
-                "Failed to find InitialTransitionForCurrentPlan id = %s",
-                getId().toString()));
+
+        throw new EntitlementError(String.format("Failed to find InitialTransitionForCurrentPlan id = %s", getId()));
     }
 
     public boolean isSubscriptionFutureCancelled() {
@@ -482,10 +480,9 @@ public class SubscriptionData extends EntityBase implements Subscription {
                 nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, cur.getRequestedDate(), getStartDate()) : null;
                 nextPriceList = (nextPriceListName != null) ? catalog.findPriceList(nextPriceListName, cur.getRequestedDate()) : null;
             } catch (CatalogApiException e) {
-                log.error(String.format(
-                        "Failed to build transition for subscription %s", id),
-                          e);
+                log.error(String.format("Failed to build transition for subscription %s", id), e);
             }
+
             final SubscriptionTransitionData transition = new SubscriptionTransitionData(
                     cur.getId(), id, bundleId, cur.getType(), apiEventType,
                     cur.getRequestedDate(), cur.getEffectiveDate(),
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvents.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvents.java
index 31d664d..dae1ddf 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvents.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvents.java
@@ -17,21 +17,19 @@
 package com.ning.billing.entitlement.api.user;
 
 import java.util.LinkedList;
+import java.util.List;
 import java.util.UUID;
 
 import com.ning.billing.entitlement.events.EntitlementEvent;
 
 public class SubscriptionEvents {
-
     public static final long INITIAL_VERSION = 1;
 
-    private final LinkedList<EntitlementEvent> events;
+    private final List<EntitlementEvent> events;
 
     private long activeVersion;
 
-    public SubscriptionEvents(final UUID subscriptionId) {
-        super();
-        final UUID subscriptionId1 = subscriptionId;
+    public SubscriptionEvents() {
         this.events = new LinkedList<EntitlementEvent>();
         this.activeVersion = INITIAL_VERSION;
     }
@@ -40,22 +38,21 @@ public class SubscriptionEvents {
         events.add(ev);
     }
 
-    public LinkedList<EntitlementEvent> getCurrentView() {
+    public List<EntitlementEvent> getCurrentView() {
         return getViewForVersion(activeVersion);
     }
 
-    public LinkedList<EntitlementEvent> getViewForVersion(final long version) {
-
+    public List<EntitlementEvent> getViewForVersion(final long version) {
         final LinkedList<EntitlementEvent> result = new LinkedList<EntitlementEvent>();
         for (final EntitlementEvent cur : events) {
             if (cur.getActiveVersion() == version) {
                 result.add(cur);
             }
         }
+
         return result;
     }
 
-
     public long getActiveVersion() {
         return activeVersion;
     }
@@ -63,4 +60,42 @@ public class SubscriptionEvents {
     public void setActiveVersion(final long activeVersion) {
         this.activeVersion = activeVersion;
     }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SubscriptionEvents");
+        sb.append("{activeVersion=").append(activeVersion);
+        sb.append(", events=").append(events);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final SubscriptionEvents that = (SubscriptionEvents) o;
+
+        if (activeVersion != that.activeVersion) {
+            return false;
+        }
+        if (events != null ? !events.equals(that.events) : that.events != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = events != null ? events.hashCode() : 0;
+        result = 31 * result + (int) (activeVersion ^ (activeVersion >>> 32));
+        return result;
+    }
 }
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 44079d8..fd86f63 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
@@ -17,8 +17,6 @@
 package com.ning.billing.entitlement.engine.addon;
 
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
@@ -32,9 +30,6 @@ import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 
 public class AddonUtils {
-
-    private static final Logger logger = LoggerFactory.getLogger(AddonUtils.class);
-
     private final CatalogService catalogService;
 
     @Inject
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
index 38bf0ca..2d7f212 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
@@ -17,7 +17,6 @@
 package com.ning.billing.entitlement.engine.dao;
 
 import javax.annotation.Nullable;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -90,10 +89,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
     private final Bus eventBus;
 
     @Inject
-    public AuditedEntitlementDao(final IDBI dbi, final Clock clock,
-            final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
-            final Bus eventBus) {
-
+    public AuditedEntitlementDao(final IDBI dbi, final Clock clock, final AddonUtils addonUtils,
+                                 final NotificationQueueService notificationQueueService, final Bus eventBus) {
         this.clock = clock;
         this.subscriptionsDao = dbi.onDemand(SubscriptionSqlDao.class);
         this.eventsDao = dbi.onDemand(EntitlementEventSqlDao.class);
@@ -109,8 +106,7 @@ public class AuditedEntitlementDao implements EntitlementDao {
     }
 
     @Override
-    public List<SubscriptionBundle> getSubscriptionBundleForAccount(
-            final UUID accountId) {
+    public List<SubscriptionBundle> getSubscriptionBundleForAccount(final UUID accountId) {
         return bundlesDao.getBundleFromAccount(accountId.toString());
     }
 
@@ -179,18 +175,17 @@ public class AuditedEntitlementDao implements EntitlementDao {
         if (bundle == null) {
             return Collections.emptyList();
         }
+
         return getSubscriptions(factory, bundle.getId());
     }
 
     @Override
     public void updateChargedThroughDate(final SubscriptionData subscription, final CallContext context) {
-
         final Date ctd = (subscription.getChargedThroughDate() != null) ? subscription.getChargedThroughDate().toDate() : null;
 
         subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
             @Override
-            public Void inTransaction(final SubscriptionSqlDao transactionalDao,
-                    final TransactionStatus status) throws Exception {
+            public Void inTransaction(final SubscriptionSqlDao transactionalDao, final TransactionStatus status) throws Exception {
                 final String subscriptionId = subscription.getId().toString();
                 transactionalDao.updateChargedThroughDate(subscription.getId().toString(), ctd, context);
                 final Long subscriptionRecordId = transactionalDao.getRecordId(subscriptionId);
@@ -200,10 +195,11 @@ public class AuditedEntitlementDao implements EntitlementDao {
                 final BundleSqlDao bundleSqlDao = transactionalDao.become(BundleSqlDao.class);
                 final String bundleId = subscription.getBundleId().toString();
                 bundleSqlDao.updateBundleLastSysTime(bundleId, clock.getUTCNow().toDate());
-                // SubscriptionBundle bundle = bundleSqlDao.getById(bundleId);
+
                 final Long recordId = bundleSqlDao.getRecordId(bundleId);
                 final EntityAudit bundleAudit = new EntityAudit(TableName.BUNDLES, recordId, ChangeType.UPDATE);
                 bundleSqlDao.insertAuditFromTransaction(bundleAudit, context);
+
                 return null;
             }
         });
@@ -222,8 +218,9 @@ public class AuditedEntitlementDao implements EntitlementDao {
                 transactional.insertAuditFromTransaction(audit, context);
 
                 recordFutureNotificationFromTransaction(transactional,
-                        nextPhase.getEffectiveDate(),
-                        new EntitlementNotificationKey(nextPhase.getId()));
+                                                        nextPhase.getEffectiveDate(),
+                                                        new EntitlementNotificationKey(nextPhase.getId()));
+
                 return null;
             }
         });
@@ -244,17 +241,19 @@ public class AuditedEntitlementDao implements EntitlementDao {
         return subscriptionsDao.inTransaction(new Transaction<Map<UUID, List<EntitlementEvent>>, SubscriptionSqlDao>() {
             @Override
             public Map<UUID, List<EntitlementEvent>> inTransaction(final SubscriptionSqlDao transactional,
-                    final TransactionStatus status) throws Exception {
+                                                                   final TransactionStatus status) throws Exception {
                 final List<Subscription> subscriptions = transactional.getSubscriptionsFromBundleId(bundleId.toString());
                 if (subscriptions.size() == 0) {
                     return Collections.emptyMap();
                 }
+
                 final EntitlementEventSqlDao eventsDaoFromSameTransaction = transactional.become(EntitlementEventSqlDao.class);
                 final Map<UUID, List<EntitlementEvent>> result = new HashMap<UUID, List<EntitlementEvent>>();
                 for (final Subscription cur : subscriptions) {
                     final List<EntitlementEvent> events = eventsDaoFromSameTransaction.getEventsForSubscription(cur.getId().toString());
                     result.put(cur.getId(), events);
                 }
+
                 return result;
             }
         });
@@ -267,16 +266,12 @@ public class AuditedEntitlementDao implements EntitlementDao {
     }
 
     @Override
-    public void createSubscription(final SubscriptionData subscription,
-            final List<EntitlementEvent> initialEvents, final CallContext context) {
-
+    public void createSubscription(final SubscriptionData subscription, final List<EntitlementEvent> initialEvents, final CallContext context) {
         subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
-
             @Override
-            public Void inTransaction(final SubscriptionSqlDao transactional,
-                    final TransactionStatus status) throws Exception {
-
+            public Void inTransaction(final SubscriptionSqlDao transactional, final TransactionStatus status) throws Exception {
                 transactional.insertSubscription(subscription, context);
+
                 final Long subscriptionRecordId = transactional.getRecordId(subscription.getId().toString());
                 final EntityAudit audit = new EntityAudit(TableName.SUBSCRIPTIONS, subscriptionRecordId, ChangeType.INSERT);
                 transactional.insertAuditFromTransaction(audit, context);
@@ -290,8 +285,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
                     final Long recordId = eventsDaoFromSameTransaction.getRecordId(cur.getId().toString());
                     audits.add(new EntityAudit(TableName.SUBSCRIPTION_EVENTS, recordId, ChangeType.INSERT));
                     recordFutureNotificationFromTransaction(transactional,
-                            cur.getEffectiveDate(),
-                            new EntitlementNotificationKey(cur.getId()));
+                                                            cur.getEffectiveDate(),
+                                                            new EntitlementNotificationKey(cur.getId()));
                 }
 
                 eventsDaoFromSameTransaction.insertAuditFromTransaction(audits, context);
@@ -301,22 +296,19 @@ public class AuditedEntitlementDao implements EntitlementDao {
     }
 
     @Override
-    public void recreateSubscription(final UUID subscriptionId,
-            final List<EntitlementEvent> recreateEvents, final CallContext context) {
-
+    public void recreateSubscription(final UUID subscriptionId, final List<EntitlementEvent> recreateEvents, final CallContext context) {
         eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
             @Override
             public Void inTransaction(final EntitlementEventSqlDao transactional,
-                    final TransactionStatus status) throws Exception {
-
+                                      final TransactionStatus status) throws Exception {
                 final List<EntityAudit> audits = new ArrayList<EntityAudit>();
                 for (final EntitlementEvent cur : recreateEvents) {
                     transactional.insertEvent(cur, context);
                     final Long recordId = transactional.getRecordId(cur.getId().toString());
                     audits.add(new EntityAudit(TableName.SUBSCRIPTION_EVENTS, recordId, ChangeType.INSERT));
                     recordFutureNotificationFromTransaction(transactional,
-                            cur.getEffectiveDate(),
-                            new EntitlementNotificationKey(cur.getId()));
+                                                            cur.getEffectiveDate(),
+                                                            new EntitlementNotificationKey(cur.getId()));
 
                 }
 
@@ -328,11 +320,9 @@ public class AuditedEntitlementDao implements EntitlementDao {
 
     @Override
     public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context, final int seqId) {
-
         eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
             @Override
-            public Void inTransaction(final EntitlementEventSqlDao transactional,
-                    final TransactionStatus status) throws Exception {
+            public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
                 cancelNextCancelEventFromTransaction(subscriptionId, transactional, context);
                 cancelNextChangeEventFromTransaction(subscriptionId, transactional, context);
                 cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
@@ -344,8 +334,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
                 transactional.insertAuditFromTransaction(audit, context);
 
                 recordFutureNotificationFromTransaction(transactional,
-                        cancelEvent.getEffectiveDate(),
-                        new EntitlementNotificationKey(cancelEvent.getId(), seqId));
+                                                        cancelEvent.getEffectiveDate(),
+                                                        new EntitlementNotificationKey(cancelEvent.getId(), seqId));
                 return null;
             }
         });
@@ -353,13 +343,9 @@ public class AuditedEntitlementDao implements EntitlementDao {
 
     @Override
     public void uncancelSubscription(final UUID subscriptionId, final List<EntitlementEvent> uncancelEvents, final CallContext context) {
-
         eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
-
             @Override
-            public Void inTransaction(final EntitlementEventSqlDao transactional,
-                    final TransactionStatus status) throws Exception {
-
+            public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
                 EntitlementEvent cancelledEvent = null;
                 final Date now = clock.getUTCNow().toDate();
                 final List<EntitlementEvent> events = transactional.getFutureActiveEventForSubscription(subscriptionId.toString(), now);
@@ -386,8 +372,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
                         final Long recordId = transactional.getRecordId(cur.getId().toString());
                         eventAudits.add(new EntityAudit(TableName.SUBSCRIPTION_EVENTS, recordId, ChangeType.INSERT));
                         recordFutureNotificationFromTransaction(transactional,
-                                cur.getEffectiveDate(),
-                                new EntitlementNotificationKey(cur.getId()));
+                                                                cur.getEffectiveDate(),
+                                                                new EntitlementNotificationKey(cur.getId()));
                     }
 
                     transactional.insertAuditFromTransaction(eventAudits, context);
@@ -412,8 +398,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
                     eventAudits.add(new EntityAudit(TableName.SUBSCRIPTION_EVENTS, recordId, ChangeType.INSERT));
 
                     recordFutureNotificationFromTransaction(transactional,
-                            cur.getEffectiveDate(),
-                            new EntitlementNotificationKey(cur.getId()));
+                                                            cur.getEffectiveDate(),
+                                                            new EntitlementNotificationKey(cur.getId()));
                 }
 
                 transactional.insertAuditFromTransaction(eventAudits, context);
@@ -434,10 +420,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
         cancelFutureEventFromTransaction(subscriptionId, dao, EventType.API_USER, ApiEventType.CANCEL, context);
     }
 
-    private void cancelFutureEventFromTransaction(final UUID subscriptionId, final EntitlementEventSqlDao dao,
-            final EventType type, @Nullable final ApiEventType apiType,
-            final CallContext context) {
-
+    private void cancelFutureEventFromTransaction(final UUID subscriptionId, final EntitlementEventSqlDao dao, final EventType type,
+                                                  @Nullable final ApiEventType apiType, final CallContext context) {
         EntitlementEvent futureEvent = null;
         final Date now = clock.getUTCNow().toDate();
         final List<EntitlementEvent> events = dao.getFutureActiveEventForSubscription(subscriptionId.toString(), now);
@@ -445,9 +429,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
             if (cur.getType() == type &&
                     (apiType == null || apiType == ((ApiEvent) cur).getEventType())) {
                 if (futureEvent != null) {
-                    throw new EntitlementError(
-                            String.format("Found multiple future events for type %s for subscriptions %s",
-                                    type, subscriptionId.toString()));
+                    throw new EntitlementError(String.format("Found multiple future events for type %s for subscriptions %s",
+                                                             type, subscriptionId.toString()));
                 }
                 futureEvent = cur;
             }
@@ -466,6 +449,7 @@ public class AuditedEntitlementDao implements EntitlementDao {
         if (input == null) {
             return null;
         }
+
         final List<Subscription> bundleInput = new ArrayList<Subscription>();
         if (input.getCategory() == ProductCategory.ADD_ON) {
             final Subscription baseSubscription = getBaseSubscription(factory, input.getBundleId(), false);
@@ -474,19 +458,22 @@ public class AuditedEntitlementDao implements EntitlementDao {
         } else {
             bundleInput.add(input);
         }
+
         final List<Subscription> reloadedSubscriptions = buildBundleSubscriptions(factory, bundleInput);
         for (final Subscription cur : reloadedSubscriptions) {
             if (cur.getId().equals(input.getId())) {
                 return cur;
             }
         }
-        throw new EntitlementError(String.format("Unexpected code path in buildSubscription"));
+
+        throw new EntitlementError("Unexpected code path in buildSubscription");
     }
 
     private List<Subscription> buildBundleSubscriptions(final SubscriptionFactory factory, final List<Subscription> input) {
         if (input == null || input.size() == 0) {
             return Collections.emptyList();
         }
+
         // Make sure BasePlan -- if exists-- is first
         Collections.sort(input, new Comparator<Subscription>() {
             @Override
@@ -504,67 +491,63 @@ public class AuditedEntitlementDao implements EntitlementDao {
         EntitlementEvent futureBaseEvent = null;
         final List<Subscription> result = new ArrayList<Subscription>(input.size());
         for (final Subscription cur : input) {
-
             final List<EntitlementEvent> events = eventsDao.getEventsForSubscription(cur.getId().toString());
             Subscription reloaded = factory.createSubscription(new SubscriptionBuilder((SubscriptionData) cur), events);
 
             switch (cur.getCategory()) {
-            case BASE:
-                final Collection<EntitlementEvent> futureApiEvents = Collections2.filter(events, new Predicate<EntitlementEvent>() {
-                    @Override
-                    public boolean apply(final EntitlementEvent input) {
-                        return (input.getEffectiveDate().isAfter(clock.getUTCNow()) &&
-                                ((input instanceof ApiEventCancel) || (input instanceof ApiEventChange)));
-                    }
-                });
-                futureBaseEvent = (futureApiEvents.size() == 0) ? null : futureApiEvents.iterator().next();
-                break;
-
-            case ADD_ON:
-                final Plan targetAddOnPlan = reloaded.getCurrentPlan();
-                final String baseProductName = (futureBaseEvent instanceof ApiEventChange) ?
-                        ((ApiEventChange) futureBaseEvent).getEventPlan() : null;
-
-                        final boolean createCancelEvent = (futureBaseEvent != null) &&
-                        ((futureBaseEvent instanceof ApiEventCancel) ||
-                                ((!addonUtils.isAddonAvailableFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
-                                        (addonUtils.isAddonIncludedFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
-
-                        if (createCancelEvent) {
-                            final DateTime now = clock.getUTCNow();
-                            final 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);
+                case BASE:
+                    final Collection<EntitlementEvent> futureApiEvents = Collections2.filter(events, new Predicate<EntitlementEvent>() {
+                        @Override
+                        public boolean apply(final EntitlementEvent input) {
+                            return (input.getEffectiveDate().isAfter(clock.getUTCNow()) &&
+                                    ((input instanceof ApiEventCancel) || (input instanceof ApiEventChange)));
                         }
-                        break;
-            default:
-                break;
+                    });
+                    futureBaseEvent = (futureApiEvents.size() == 0) ? null : futureApiEvents.iterator().next();
+                    break;
+
+                case ADD_ON:
+                    final Plan targetAddOnPlan = reloaded.getCurrentPlan();
+                    final String baseProductName = (futureBaseEvent instanceof ApiEventChange) ?
+                            ((ApiEventChange) futureBaseEvent).getEventPlan() : null;
+
+                    final boolean createCancelEvent = (futureBaseEvent != null) &&
+                            ((futureBaseEvent instanceof ApiEventCancel) ||
+                                    ((!addonUtils.isAddonAvailableFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
+                                            (addonUtils.isAddonIncludedFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
+
+                    if (createCancelEvent) {
+                        final DateTime now = clock.getUTCNow();
+                        final 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;
             }
 
             result.add(reloaded);
         }
+
         return result;
     }
 
     @Override
     public void migrate(final UUID accountId, final AccountMigrationData accountData, final CallContext context) {
-
         eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
-
             @Override
-            public Void inTransaction(final EntitlementEventSqlDao transactional,
-                    final TransactionStatus status) throws Exception {
-
+            public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
                 final SubscriptionSqlDao transSubDao = transactional.become(SubscriptionSqlDao.class);
                 final BundleSqlDao transBundleDao = transactional.become(BundleSqlDao.class);
 
@@ -584,8 +567,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
                             audits.add(new EntityAudit(TableName.SUBSCRIPTION_EVENTS, recordId, ChangeType.INSERT));
 
                             recordFutureNotificationFromTransaction(transactional,
-                                    curEvent.getEffectiveDate(),
-                                    new EntitlementNotificationKey(curEvent.getId()));
+                                                                    curEvent.getEffectiveDate(),
+                                                                    new EntitlementNotificationKey(curEvent.getId()));
                         }
                         transSubDao.insertSubscription(subData, context);
                         recordId = transSubDao.getRecordId(subData.getId().toString());
@@ -606,11 +589,8 @@ public class AuditedEntitlementDao implements EntitlementDao {
 
     public void repair(final UUID accountId, final UUID bundleId, final List<SubscriptionDataRepair> inRepair, final CallContext context) {
         subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
-
             @Override
-            public Void inTransaction(final SubscriptionSqlDao transactional,
-                    final TransactionStatus status) throws Exception {
-
+            public Void inTransaction(final SubscriptionSqlDao transactional, final TransactionStatus status) throws Exception {
                 final EntitlementEventSqlDao transEventDao = transactional.become(EntitlementEventSqlDao.class);
                 for (final SubscriptionDataRepair cur : inRepair) {
                     transactional.updateForRepair(cur.getId().toString(), cur.getActiveVersion(), cur.getStartDate().toDate(), cur.getBundleStartDate().toDate(), context);
@@ -621,17 +601,19 @@ public class AuditedEntitlementDao implements EntitlementDao {
                         transEventDao.insertEvent(event, context);
                         if (event.getEffectiveDate().isAfter(clock.getUTCNow())) {
                             recordFutureNotificationFromTransaction(transactional,
-                                    event.getEffectiveDate(),
-                                    new EntitlementNotificationKey(event.getId()));
+                                                                    event.getEffectiveDate(),
+                                                                    new EntitlementNotificationKey(event.getId()));
                         }
                     }
                 }
+
                 try {
                     final RepairEntitlementEvent busEvent = new DefaultRepairEntitlementEvent(context.getUserToken(), accountId, bundleId, clock.getUTCNow());
                     eventBus.postFromTransaction(busEvent, transactional);
                 } catch (EventBusException e) {
                     log.warn("Failed to post repair entitlement event for bundle " + bundleId, e);
                 }
+
                 return null;
             }
         });
@@ -644,13 +626,14 @@ public class AuditedEntitlementDao implements EntitlementDao {
                 return rebuildSubscription ? buildSubscription(factory, cur) : cur;
             }
         }
+
         return null;
     }
 
     private void recordFutureNotificationFromTransaction(final Transmogrifier transactionalDao, final DateTime effectiveDate, final NotificationKey notificationKey) {
         try {
             final 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);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
index 3530c28..b80a18f 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
@@ -29,7 +29,7 @@ import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.Binder;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
-import org.skife.jdbi.v2.sqlobject.customizers.Mapper;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
@@ -45,11 +45,10 @@ import com.ning.billing.util.dao.BinderBase;
 import com.ning.billing.util.dao.MapperBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 
-
 @ExternalizedSqlViaStringTemplate3()
+@RegisterMapper(BundleSqlDao.ISubscriptionBundleSqlMapper.class)
 public interface BundleSqlDao extends Transactional<BundleSqlDao>, EntitySqlDao<SubscriptionBundle>,
-        AuditSqlDao, CloseMe, Transmogrifier {
-
+                                      AuditSqlDao, CloseMe, Transmogrifier {
     @SqlUpdate
     public void insertBundle(@Bind(binder = SubscriptionBundleBinder.class) SubscriptionBundleData bundle,
                              @CallContextBinder final CallContext context);
@@ -58,22 +57,18 @@ public interface BundleSqlDao extends Transactional<BundleSqlDao>, EntitySqlDao<
     public void updateBundleLastSysTime(@Bind("id") String id, @Bind("lastSysUpdateDate") Date lastSysUpdate);
 
     @SqlQuery
-    @Mapper(ISubscriptionBundleSqlMapper.class)
     public SubscriptionBundle getBundleFromId(@Bind("id") String id);
 
     @SqlQuery
-    @Mapper(ISubscriptionBundleSqlMapper.class)
     public SubscriptionBundle getBundleFromKey(@Bind("externalKey") String externalKey);
 
     @SqlQuery
-    @Mapper(ISubscriptionBundleSqlMapper.class)
     public List<SubscriptionBundle> getBundleFromAccount(@Bind("accountId") String accountId);
 
     public static class SubscriptionBundleBinder extends BinderBase implements Binder<Bind, SubscriptionBundleData> {
         @Override
         public void bind(@SuppressWarnings("rawtypes") final SQLStatement stmt, final Bind bind, final SubscriptionBundleData bundle) {
             stmt.bind("id", bundle.getId().toString());
-            stmt.bind("startDate", getDate(bundle.getStartDate()));
             stmt.bind("externalKey", bundle.getKey());
             stmt.bind("accountId", bundle.getAccountId().toString());
             stmt.bind("lastSysUpdateDate", getDate(bundle.getLastSysUpdateTime()));
@@ -81,17 +76,13 @@ public interface BundleSqlDao extends Transactional<BundleSqlDao>, EntitySqlDao<
     }
 
     public static class ISubscriptionBundleSqlMapper extends MapperBase implements ResultSetMapper<SubscriptionBundle> {
-
         @Override
-        public SubscriptionBundle map(final int arg, final ResultSet r,
-                                      final StatementContext ctx) throws SQLException {
+        public SubscriptionBundle map(final int arg, final ResultSet r, final StatementContext ctx) throws SQLException {
             final UUID id = UUID.fromString(r.getString("id"));
             final String key = r.getString("external_key");
             final UUID accountId = UUID.fromString(r.getString("account_id"));
-            final DateTime startDate = getDate(r, "start_date");
             final DateTime lastSysUpdateDate = getDate(r, "last_sys_update_date");
-            final SubscriptionBundleData bundle = new SubscriptionBundleData(id, key, accountId, startDate, lastSysUpdateDate);
-            return bundle;
+            return new SubscriptionBundleData(id, key, accountId, lastSysUpdateDate);
         }
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
index d6f3fe9..653e1ca 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.entitlement.engine.dao;
 
 import java.util.Collections;
@@ -38,11 +39,11 @@ import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.callcontext.CallContext;
 
 public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLifecycleDao {
+    private static final String NOT_IMPLEMENTED = "Not implemented";
 
     private final ThreadLocal<Map<UUID, SubscriptionRepairEvent>> preThreadsInRepairSubscriptions = new ThreadLocal<Map<UUID, SubscriptionRepairEvent>>();
 
     private static final class SubscriptionRepairEvent {
-
         private final Set<EntitlementEvent> events;
 
         public SubscriptionRepairEvent(final List<EntitlementEvent> initialEvents) {
@@ -112,7 +113,6 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
         }
     }
 
-
     @Override
     public void changePlan(final UUID subscriptionId,
                            final List<EntitlementEvent> changeEvents, final CallContext context) {
@@ -136,108 +136,104 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
         map.clear();
     }
 
-
     private void addEvents(final UUID subscriptionId, final List<EntitlementEvent> events) {
         final SubscriptionRepairEvent target = getRepairSubscriptionEvents(subscriptionId);
         target.addEvents(events);
     }
 
-
     @Override
     public void uncancelSubscription(final UUID subscriptionId,
                                      final List<EntitlementEvent> uncancelEvents, final CallContext context) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public List<SubscriptionBundle> getSubscriptionBundleForAccount(final UUID accountId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public SubscriptionBundle getSubscriptionBundleFromKey(final String bundleKey) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public SubscriptionBundle getSubscriptionBundleFromId(final UUID bundleId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public SubscriptionBundle createSubscriptionBundle(
             final SubscriptionBundleData bundle, final CallContext context) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public Subscription getSubscriptionFromId(final SubscriptionFactory factory,
                                               final UUID subscriptionId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public UUID getAccountIdFromSubscriptionId(final UUID subscriptionId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public Subscription getBaseSubscription(final SubscriptionFactory factory,
                                             final UUID bundleId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public List<Subscription> getSubscriptions(final SubscriptionFactory factory,
                                                final UUID bundleId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public List<Subscription> getSubscriptionsForKey(
             final SubscriptionFactory factory, final String bundleKey) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public void updateChargedThroughDate(final SubscriptionData subscription,
                                          final CallContext context) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public void createNextPhaseEvent(final UUID subscriptionId,
                                      final EntitlementEvent nextPhase, final CallContext context) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public EntitlementEvent getEventById(final UUID eventId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public Map<UUID, List<EntitlementEvent>> getEventsForBundle(final UUID bundleId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
-
     @Override
     public List<EntitlementEvent> getPendingEventsForSubscription(
             final UUID subscriptionId) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
-
     @Override
     public void migrate(final UUID accountId, final AccountMigrationData data,
                         final CallContext context) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 
     @Override
     public void repair(final UUID accountId, final UUID bundleId, final List<SubscriptionDataRepair> inRepair,
                        final CallContext context) {
-        throw new EntitlementError("Not implemented");
+        throw new EntitlementError(NOT_IMPLEMENTED);
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
index ed1a0db..92b4526 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
@@ -23,7 +23,6 @@ import org.joda.time.DateTime;
 import com.ning.billing.entitlement.events.user.ApiEvent;
 
 public abstract class EventBase implements EntitlementEvent {
-
     private final long totalOrdering;
     private final UUID uuid;
     private final UUID subscriptionId;
@@ -41,30 +40,9 @@ public abstract class EventBase implements EntitlementEvent {
         this.requestedDate = builder.getRequestedDate();
         this.effectiveDate = builder.getEffectiveDate();
         this.processedDate = builder.getProcessedDate();
-
         this.activeVersion = builder.getActiveVersion();
         this.isActive = builder.isActive();
     }
-/*
-    public EventBase(UUID subscriptionId, DateTime requestedDate,
-            DateTime effectiveDate, DateTime processedDate,
-            long activeVersion, boolean isActive) {
-        this(UUID.randomUUID(), subscriptionId, requestedDate, effectiveDate, processedDate, activeVersion, isActive);
-    }
-
-    public EventBase(UUID id, UUID subscriptionId, DateTime requestedDate,
-            DateTime effectiveDate, DateTime processedDate,
-            long activeVersion, boolean isActive) {
-        this.uuid = id;
-        this.subscriptionId = subscriptionId;
-        this.requestedDate = requestedDate;
-        this.effectiveDate = effectiveDate;
-        this.processedDate = processedDate;
-
-        this.activeVersion = activeVersion;
-        this.isActive = isActive;
-    }
-*/
 
     @Override
     public DateTime getRequestedDate() {
@@ -91,7 +69,6 @@ public abstract class EventBase implements EntitlementEvent {
         return totalOrdering;
     }
 
-
     @Override
     public UUID getId() {
         return uuid;
@@ -122,7 +99,6 @@ public abstract class EventBase implements EntitlementEvent {
         this.isActive = true;
     }
 
-
     //
     // Really used for unit tests only as the sql implementation relies on date first and then event insertion
     //
@@ -135,7 +111,7 @@ public abstract class EventBase implements EntitlementEvent {
     @Override
     public int compareTo(final EntitlementEvent other) {
         if (other == null) {
-            throw new NullPointerException("IEvent is compared to a null instance");
+            throw new IllegalArgumentException("IEvent is compared to a null instance");
         }
 
         if (effectiveDate.isBefore(other.getEffectiveDate())) {
@@ -159,7 +135,6 @@ public abstract class EventBase implements EntitlementEvent {
         }
     }
 
-
     @Override
     public boolean equals(final Object other) {
         if (!(other instanceof EntitlementEvent)) {
@@ -170,6 +145,4 @@ public abstract class EventBase implements EntitlementEvent {
 
     @Override
     public abstract EventType getType();
-
-
 }
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 ae45518..66628e8 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
@@ -51,7 +51,6 @@ DROP TABLE IF EXISTS bundles;
 CREATE TABLE bundles (
     record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     id char(36) NOT NULL,
-    start_date datetime, /*NOT NULL*/
     external_key varchar(64) NOT NULL,
     account_id char(36) NOT NULL,
     last_sys_update_date datetime,
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg
index 367330f..1ecf151 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg
@@ -2,7 +2,6 @@ group BundleSqlDao;
 
 fields(prefix) ::= <<
     <prefix>id,
-    <prefix>start_date,
     <prefix>external_key,
     <prefix>account_id,
     <prefix>last_sys_update_date
@@ -10,7 +9,7 @@ fields(prefix) ::= <<
 
 insertBundle() ::= <<
     insert into bundles (<fields()>)
-    values (:id, :startDate, :externalKey, :accountId, :lastSysUpdateDate);
+    values (:id, :externalKey, :accountId, :lastSysUpdateDate);
 >>
 
 updateBundleLastSysTime()  ::= <<
@@ -65,4 +64,4 @@ auditFields(prefix) ::= <<
 insertAuditFromTransaction() ::= <<
     INSERT INTO audit_log(<auditFields()>)
     VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, :reasonCode, :comment, :userToken);
->>
\ No newline at end of file
+>>
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
new file mode 100644
index 0000000..571630f
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2010-2012 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.alignment;
+
+import java.util.List;
+import java.util.Map;
+
+import org.joda.time.DateTime;
+import org.skife.config.ConfigSource;
+import org.skife.config.ConfigurationObjectFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.ning.billing.catalog.DefaultCatalogService;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.io.VersionedCatalogLoader;
+import com.ning.billing.config.CatalogConfig;
+import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
+import com.ning.billing.entitlement.events.EntitlementEvent;
+import com.ning.billing.entitlement.events.user.ApiEventBase;
+import com.ning.billing.entitlement.events.user.ApiEventBuilder;
+import com.ning.billing.entitlement.events.user.ApiEventType;
+import com.ning.billing.entitlement.exceptions.EntitlementError;
+import com.ning.billing.util.clock.DefaultClock;
+
+public class TestPlanAligner {
+    private static final String priceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+    private final DefaultClock clock = new DefaultClock();
+
+    private DefaultCatalogService catalogService;
+    private PlanAligner planAligner;
+
+    @BeforeClass(groups = "fast")
+    public void setUp() throws Exception {
+        final VersionedCatalogLoader versionedCatalogLoader = new VersionedCatalogLoader(clock);
+        final CatalogConfig config = new ConfigurationObjectFactory(new ConfigSource() {
+            final Map<String, String> properties = ImmutableMap.<String, String>of("killbill.catalog.uri", "file:src/test/resources/testInput.xml");
+
+            @Override
+            public String getString(final String propertyName) {
+                return properties.get(propertyName);
+            }
+        }).build(CatalogConfig.class);
+
+        catalogService = new DefaultCatalogService(config, versionedCatalogLoader);
+        planAligner = new PlanAligner(catalogService);
+
+        catalogService.loadCatalog();
+    }
+
+    @Test(groups = "fast")
+    public void testCreationBundleAlignment() throws Exception {
+        final String productName = "pistol-monthly";
+        final PhaseType initialPhase = PhaseType.TRIAL;
+        final SubscriptionData subscriptionData = createSubscriptionStartedInThePast(productName, initialPhase);
+
+        // Make the creation effective now, after the bundle and the subscription started
+        final DateTime effectiveDate = clock.getUTCNow();
+        final TimedPhase[] phases = getTimedPhasesOnCreate(productName, initialPhase, subscriptionData, effectiveDate);
+
+        // All plans but Laser-Scope are START_OF_BUNDLE aligned on creation
+        Assert.assertEquals(phases[0].getStartPhase(), subscriptionData.getBundleStartDate());
+        Assert.assertEquals(phases[1].getStartPhase(), subscriptionData.getBundleStartDate().plusDays(30));
+
+        // Verify the next phase via the other API
+        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(subscriptionData, effectiveDate, effectiveDate);
+        Assert.assertEquals(nextTimePhase.getStartPhase(), subscriptionData.getBundleStartDate().plusDays(30));
+
+        // Now look at the past, before the bundle started
+        final DateTime effectiveDateInThePast = subscriptionData.getBundleStartDate().minusHours(10);
+        final TimedPhase[] phasesInThePast = getTimedPhasesOnCreate(productName, initialPhase, subscriptionData, effectiveDateInThePast);
+        Assert.assertNull(phasesInThePast[0]);
+        Assert.assertEquals(phasesInThePast[1].getStartPhase(), subscriptionData.getBundleStartDate());
+
+        // Verify the next phase via the other API
+        try {
+            planAligner.getNextTimedPhase(subscriptionData, effectiveDateInThePast, effectiveDateInThePast);
+            Assert.fail("Can't use getNextTimedPhase(): the effective date is before the initial plan");
+        } catch (EntitlementError e) {
+            Assert.assertTrue(true);
+        }
+
+        // Try a change plan now (simulate an IMMEDIATE policy)
+        final String newProductName = "shotgun-monthly";
+        final DateTime effectiveChangeDate = clock.getUTCNow();
+        changeSubscription(effectiveChangeDate, subscriptionData, productName, newProductName, initialPhase);
+
+        // All non rescue plans are START_OF_SUBSCRIPTION aligned on change
+        final TimedPhase newPhase = getNextTimedPhaseOnChange(subscriptionData, newProductName, effectiveChangeDate);
+        Assert.assertEquals(newPhase.getStartPhase(), subscriptionData.getStartDate().plusDays(30),
+                            String.format("Start phase: %s, but bundle start date: %s and subscription start date: %s",
+                                          newPhase.getStartPhase(), subscriptionData.getBundleStartDate(), subscriptionData.getStartDate()));
+    }
+
+    @Test(groups = "fast")
+    public void testCreationSubscriptionAlignment() throws Exception {
+        final String productName = "laser-scope-monthly";
+        final PhaseType initialPhase = PhaseType.DISCOUNT;
+        final SubscriptionData subscriptionData = createSubscriptionStartedInThePast(productName, initialPhase);
+
+        // Look now, after the bundle and the subscription started
+        final DateTime effectiveDate = clock.getUTCNow();
+        final TimedPhase[] phases = getTimedPhasesOnCreate(productName, initialPhase, subscriptionData, effectiveDate);
+
+        // Laser-Scope is START_OF_SUBSCRIPTION aligned on creation
+        Assert.assertEquals(phases[0].getStartPhase(), subscriptionData.getStartDate());
+        Assert.assertEquals(phases[1].getStartPhase(), subscriptionData.getStartDate().plusDays(30));
+
+        // Verify the next phase via the other API
+        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(subscriptionData, effectiveDate, effectiveDate);
+        Assert.assertEquals(nextTimePhase.getStartPhase(), subscriptionData.getStartDate().plusDays(30));
+
+        // Now look at the past, before the subscription started
+        final DateTime effectiveDateInThePast = subscriptionData.getStartDate().minusHours(10);
+        final TimedPhase[] phasesInThePast = getTimedPhasesOnCreate(productName, initialPhase, subscriptionData, effectiveDateInThePast);
+        Assert.assertNull(phasesInThePast[0]);
+        Assert.assertEquals(phasesInThePast[1].getStartPhase(), subscriptionData.getStartDate());
+
+        // Verify the next phase via the other API
+        try {
+            planAligner.getNextTimedPhase(subscriptionData, effectiveDateInThePast, effectiveDateInThePast);
+            Assert.fail("Can't use getNextTimedPhase(): the effective date is before the initial plan");
+        } catch (EntitlementError e) {
+            Assert.assertTrue(true);
+        }
+
+        // Try a change plan (simulate END_OF_TERM policy)
+        final String newProductName = "telescopic-scope-monthly";
+        final DateTime effectiveChangeDate = subscriptionData.getStartDate().plusDays(30);
+        changeSubscription(effectiveChangeDate, subscriptionData, productName, newProductName, initialPhase);
+
+        // All non rescue plans are START_OF_SUBSCRIPTION aligned on change. Since we're END_OF_TERM here, we'll
+        // never see the discount phase of telescopic-scope-monthly and jump right into evergreen.
+        // But in this test, since we didn't create the future change event from discount to evergreen (see changeSubscription,
+        // the subscription has only two transitions), we'll see null
+        final TimedPhase newPhase = getNextTimedPhaseOnChange(subscriptionData, newProductName, effectiveChangeDate);
+        Assert.assertNull(newPhase);
+    }
+
+    private SubscriptionData createSubscriptionStartedInThePast(final String productName, final PhaseType phaseType) {
+        final DefaultSubscriptionFactory.SubscriptionBuilder builder = new DefaultSubscriptionFactory.SubscriptionBuilder();
+        builder.setBundleStartDate(clock.getUTCNow().minusHours(10));
+        // Make sure to set the dates apart
+        builder.setStartDate(new DateTime(builder.getBundleStartDate().plusHours(5)));
+
+        // Create the transitions
+        final SubscriptionData subscriptionData = new SubscriptionData(builder, null, clock);
+        final EntitlementEvent event = createEntitlementEvent(builder.getStartDate(),
+                                                              productName,
+                                                              phaseType,
+                                                              ApiEventType.CREATE,
+                                                              subscriptionData.getActiveVersion());
+        subscriptionData.rebuildTransitions(ImmutableList.<EntitlementEvent>of(event), catalogService.getFullCatalog());
+
+        Assert.assertEquals(subscriptionData.getAllTransitions().size(), 1);
+        Assert.assertNull(subscriptionData.getAllTransitions().get(0).getPreviousPhase());
+        Assert.assertNotNull(subscriptionData.getAllTransitions().get(0).getNextPhase());
+
+        return subscriptionData;
+    }
+
+    private void changeSubscription(final DateTime effectiveChangeDate,
+                                    final SubscriptionData subscriptionData,
+                                    final String previousProductName,
+                                    final String newProductName,
+                                    final PhaseType commonPhaseType) {
+        final EntitlementEvent previousEvent = createEntitlementEvent(subscriptionData.getStartDate(),
+                                                                      previousProductName,
+                                                                      commonPhaseType,
+                                                                      ApiEventType.CREATE,
+                                                                      subscriptionData.getActiveVersion());
+        final EntitlementEvent event = createEntitlementEvent(effectiveChangeDate,
+                                                              newProductName,
+                                                              commonPhaseType,
+                                                              ApiEventType.CHANGE,
+                                                              subscriptionData.getActiveVersion());
+
+        subscriptionData.rebuildTransitions(ImmutableList.<EntitlementEvent>of(previousEvent, event), catalogService.getFullCatalog());
+
+        final List<SubscriptionTransitionData> newTransitions = subscriptionData.getAllTransitions();
+        Assert.assertEquals(newTransitions.size(), 2);
+        Assert.assertNull(newTransitions.get(0).getPreviousPhase());
+        Assert.assertEquals(newTransitions.get(0).getNextPhase(), newTransitions.get(1).getPreviousPhase());
+        Assert.assertNotNull(newTransitions.get(1).getNextPhase());
+    }
+
+    private EntitlementEvent createEntitlementEvent(final DateTime effectiveDate,
+                                                    final String productName,
+                                                    final PhaseType phaseType,
+                                                    final ApiEventType apiEventType,
+                                                    final long activeVersion) {
+        final ApiEventBuilder eventBuilder = new ApiEventBuilder();
+        eventBuilder.setEffectiveDate(effectiveDate);
+        eventBuilder.setEventPlan(productName);
+        eventBuilder.setEventPlanPhase(productName + "-" + phaseType.toString().toLowerCase());
+        eventBuilder.setEventPriceList(priceList);
+
+        // We don't really use the following but the code path requires it
+        eventBuilder.setRequestedDate(effectiveDate);
+        eventBuilder.setFromDisk(true);
+        eventBuilder.setActiveVersion(activeVersion);
+
+        return new ApiEventBase(eventBuilder.setEventType(apiEventType));
+    }
+
+    private TimedPhase getNextTimedPhaseOnChange(final SubscriptionData subscriptionData,
+                                                 final String newProductName,
+                                                 final DateTime effectiveChangeDate) throws CatalogApiException, EntitlementUserApiException {
+        // The date is used for different catalog versions - we don't care here
+        final Plan newPlan = catalogService.getFullCatalog().findPlan(newProductName, clock.getUTCNow());
+
+        return planAligner.getNextTimedPhaseOnChange(subscriptionData, newPlan, priceList, effectiveChangeDate, effectiveChangeDate);
+    }
+
+    private TimedPhase[] getTimedPhasesOnCreate(final String productName,
+                                                final PhaseType initialPhase,
+                                                final SubscriptionData subscriptionData,
+                                                final DateTime effectiveDate) throws CatalogApiException, EntitlementUserApiException {
+        // The date is used for different catalog versions - we don't care here
+        final Plan plan = catalogService.getFullCatalog().findPlan(productName, clock.getUTCNow());
+
+        // Same here for the requested date
+        final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscriptionData, plan, initialPhase, priceList, clock.getUTCNow(), effectiveDate);
+        Assert.assertEquals(phases.length, 2);
+
+        return phases;
+    }
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestTimedMigration.java b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestTimedMigration.java
new file mode 100644
index 0000000..09740d2
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestTimedMigration.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2012 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.alignment;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.entitlement.events.EntitlementEvent;
+import com.ning.billing.entitlement.events.user.ApiEventType;
+
+public class TestTimedMigration {
+    @Test(groups = "fast")
+    public void testConstructor() throws Exception {
+        final DateTime eventTime = new DateTime(DateTimeZone.UTC);
+        final EntitlementEvent.EventType eventType = EntitlementEvent.EventType.API_USER;
+        final ApiEventType apiEventType = ApiEventType.CREATE;
+        final Plan plan = Mockito.mock(Plan.class);
+        final PlanPhase phase = Mockito.mock(PlanPhase.class);
+        final String priceList = UUID.randomUUID().toString();
+        final TimedMigration timedMigration = new TimedMigration(eventTime, eventType, apiEventType, plan, phase, priceList);
+        final TimedMigration otherTimedMigration = new TimedMigration(eventTime, eventType, apiEventType, plan, phase, priceList);
+
+        Assert.assertEquals(otherTimedMigration, timedMigration);
+        Assert.assertEquals(timedMigration.getEventTime(), eventTime);
+        Assert.assertEquals(timedMigration.getEventType(), eventType);
+        Assert.assertEquals(timedMigration.getApiEventType(), apiEventType);
+        Assert.assertEquals(timedMigration.getPlan(), plan);
+        Assert.assertEquals(timedMigration.getPhase(), phase);
+        Assert.assertEquals(timedMigration.getPriceList(), priceList);
+    }
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestTimedPhase.java b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestTimedPhase.java
new file mode 100644
index 0000000..75831fa
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestTimedPhase.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010-2012 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.alignment;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.catalog.api.PlanPhase;
+
+public class TestTimedPhase {
+    @Test(groups = "fast")
+    public void testConstructor() throws Exception {
+        final PlanPhase planPhase = Mockito.mock(PlanPhase.class);
+        final DateTime startPhase = new DateTime(DateTimeZone.UTC);
+        final TimedPhase timedPhase = new TimedPhase(planPhase, startPhase);
+        final TimedPhase otherTimedPhase = new TimedPhase(planPhase, startPhase);
+
+        Assert.assertEquals(otherTimedPhase, timedPhase);
+        Assert.assertEquals(timedPhase.getPhase(), planPhase);
+        Assert.assertEquals(timedPhase.getStartPhase(), startPhase);
+    }
+}
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 bfbc817..1c68f2f 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
@@ -54,11 +54,11 @@ import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.api.billing.ChargeThruApi;
 import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
 import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 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.SubscriptionEvent;
 import com.ning.billing.entitlement.engine.core.Engine;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.engine.dao.MockEntitlementDao;
@@ -505,8 +505,8 @@ public abstract class TestApiBase implements TestListenerStatus {
         }
     }
 
-    protected void printSubscriptionTransitions(final List<SubscriptionEvent> transitions) {
-        for (final SubscriptionEvent cur : transitions) {
+    protected void printSubscriptionTransitions(final List<EffectiveSubscriptionEvent> transitions) {
+        for (final EffectiveSubscriptionEvent cur : transitions) {
             log.debug("Transition " + cur);
         }
     }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestEventJson.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestEventJson.java
index 978c39b..e53115f 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestEventJson.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestEventJson.java
@@ -23,9 +23,9 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.entitlement.api.timeline.DefaultRepairEntitlementEvent;
 import com.ning.billing.entitlement.api.timeline.RepairEntitlementEvent;
-import com.ning.billing.entitlement.api.user.DefaultSubscriptionEvent;
+import com.ning.billing.entitlement.api.user.DefaultEffectiveSubscriptionEvent;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.util.jackson.ObjectMapper;
 
 public class TestEventJson {
@@ -35,12 +35,12 @@ public class TestEventJson {
     public void testSubscriptionEvent() throws Exception {
 
 
-        final SubscriptionEvent e = new DefaultSubscriptionEvent(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), new DateTime(), new DateTime(),
+        final EffectiveSubscriptionEvent e = new DefaultEffectiveSubscriptionEvent(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), new DateTime(), new DateTime(),
                                                            SubscriptionState.ACTIVE, "pro", "TRIAL", "DEFAULT", SubscriptionState.CANCELLED, null, null, null, 3L, UUID.randomUUID(), SubscriptionTransitionType.CANCEL, 0, new DateTime());
 
         final String json = mapper.writeValueAsString(e);
 
-        final Class<?> claz = Class.forName(DefaultSubscriptionEvent.class.getName());
+        final Class<?> claz = Class.forName(DefaultEffectiveSubscriptionEvent.class.getName());
         final Object obj = mapper.readValue(json, claz);
         Assert.assertTrue(obj.equals(e));
 
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 68b1978..182974b 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
@@ -386,7 +386,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
-            SubscriptionEvent aoPendingTranstion = aoSubscription.getPendingTransition();
+            EffectiveSubscriptionEvent 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/TestUserApiChangePlan.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
index 5591238..59db4d7 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
@@ -495,7 +495,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
 
             final DateTime expectedNextPhaseDate = subscription.getStartDate().plusDays(30).plusMonths(6);
-            final SubscriptionEvent nextPhase = subscription.getPendingTransition();
+            final EffectiveSubscriptionEvent nextPhase = subscription.getPendingTransition();
             final DateTime nextPhaseEffectiveDate = nextPhase.getEffectiveTransitionTime();
 
             assertEquals(nextPhaseEffectiveDate, expectedNextPhaseDate);
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 7d94daa..314816a 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -35,7 +35,7 @@ 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.EntitlementBillingApiException;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
@@ -95,7 +95,7 @@ public class InvoiceDispatcher {
         VERBOSE_OUTPUT = (verboseOutputValue != null) && Boolean.parseBoolean(verboseOutputValue);
     }
 
-    public void processSubscription(final SubscriptionEvent transition,
+    public void processSubscription(final EffectiveSubscriptionEvent transition,
                                     final CallContext context) throws InvoiceApiException {
         final UUID subscriptionId = transition.getSubscriptionId();
         final DateTime targetDate = transition.getEffectiveTransitionTime();
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 601ebeb..9b4868c 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
@@ -26,7 +26,7 @@ import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.timeline.RepairEntitlementEvent;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;
@@ -55,7 +55,7 @@ public class InvoiceListener {
     }
 
     @Subscribe
-    public void handleSubscriptionTransition(final SubscriptionEvent transition) {
+    public void handleSubscriptionTransition(final EffectiveSubscriptionEvent transition) {
         try {
             //  Skip future uncancel event
             //  Skip events which are marked as not being the last one
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
index fe79b2a..969830c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
@@ -45,10 +45,10 @@ import com.ning.billing.ErrorCode;
 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.EffectiveSubscriptionEvent;
 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.SubscriptionEvent;
 import com.ning.billing.invoice.api.EmptyInvoiceEvent;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.jaxrs.json.CustomFieldJson;
@@ -289,9 +289,9 @@ public class SubscriptionResource extends JaxRsResourceBase {
         }
 
         @Override
-        public void onSubscriptionTransition(SubscriptionEvent curEvent) {
+        public void onSubscriptionTransition(EffectiveSubscriptionEvent curEventEffective) {
             log.info(String.format("Got event SubscriptionTransition token = %s, type = %s, remaining = %d ", 
-                    curEvent.getUserToken(), curEvent.getTransitionType(),  curEvent.getRemainingEventsForUserOperation())); 
+                    curEventEffective.getUserToken(), curEventEffective.getTransitionType(),  curEventEffective.getRemainingEventsForUserOperation()));
         }
 
         @Override
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
index b602820..aa03560 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
@@ -27,9 +27,9 @@ import com.ning.billing.catalog.api.PlanPhase;
 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.EffectiveSubscriptionEvent;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.junction.api.BlockingApi;
 import com.ning.billing.junction.api.BlockingApiException;
 import com.ning.billing.junction.api.BlockingState;
@@ -116,15 +116,15 @@ public class BlockingSubscription implements Subscription {
         return subscription.getCategory();
     }
 
-    public SubscriptionEvent getPendingTransition() {
+    public EffectiveSubscriptionEvent getPendingTransition() {
         return subscription.getPendingTransition();
     }
 
-    public SubscriptionEvent getPreviousTransition() {
+    public EffectiveSubscriptionEvent getPreviousTransition() {
         return subscription.getPreviousTransition();
     }
 
-    public List<SubscriptionEvent> getBillingTransitions() {
+    public List<EffectiveSubscriptionEvent> getBillingTransitions() {
         return subscription.getBillingTransitions();
     }
 
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscriptionBundle.java b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscriptionBundle.java
index 27727e7..2a26425 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscriptionBundle.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscriptionBundle.java
@@ -18,8 +18,6 @@ package com.ning.billing.junction.plumbing.api;
 
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.junction.api.BlockingApi;
 import com.ning.billing.junction.api.BlockingState;
@@ -44,10 +42,6 @@ public class BlockingSubscriptionBundle implements SubscriptionBundle {
         return subscriptionBundle.getId();
     }
 
-    public DateTime getStartDate() {
-        return subscriptionBundle.getStartDate();
-    }
-
     public String getKey() {
         return subscriptionBundle.getKey();
     }
@@ -64,4 +58,46 @@ public class BlockingSubscriptionBundle implements SubscriptionBundle {
         return blockingState;
     }
 
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("BlockingSubscriptionBundle");
+        sb.append("{blockingApi=").append(blockingApi);
+        sb.append(", subscriptionBundle=").append(subscriptionBundle);
+        sb.append(", blockingState=").append(blockingState);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final BlockingSubscriptionBundle that = (BlockingSubscriptionBundle) o;
+
+        if (blockingApi != null ? !blockingApi.equals(that.blockingApi) : that.blockingApi != null) {
+            return false;
+        }
+        if (blockingState != null ? !blockingState.equals(that.blockingState) : that.blockingState != null) {
+            return false;
+        }
+        if (subscriptionBundle != null ? !subscriptionBundle.equals(that.subscriptionBundle) : that.subscriptionBundle != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = subscriptionBundle != null ? subscriptionBundle.hashCode() : 0;
+        result = 31 * result + (blockingApi != null ? blockingApi.hashCode() : 0);
+        result = 31 * result + (blockingState != null ? blockingState.hashCode() : 0);
+        return result;
+    }
 }
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index f76c04e..67c4b66 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -33,11 +33,11 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 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.SubscriptionEvent;
 
 public class BillCycleDayCalculator {
     private static final Logger log = LoggerFactory.getLogger(BillCycleDayCalculator.class);
@@ -52,7 +52,7 @@ public class BillCycleDayCalculator {
         this.entitlementApi = entitlementApi;
     }
 
-    protected int calculateBcd(final SubscriptionBundle bundle, final Subscription subscription, final SubscriptionEvent transition, final Account account)
+    protected int calculateBcd(final SubscriptionBundle bundle, final Subscription subscription, final EffectiveSubscriptionEvent transition, final Account account)
             throws CatalogApiException, AccountApiException, EntitlementUserApiException {
 
         final Catalog catalog = catalogService.getFullCatalog();
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
index 019acc8..7aa55ff 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
@@ -37,10 +37,10 @@ import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.entitlement.api.billing.BillingEvent;
 import com.ning.billing.entitlement.api.billing.ChargeThruApi;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 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.SubscriptionEvent;
 import com.ning.billing.junction.api.BillingApi;
 import com.ning.billing.junction.api.BillingEventSet;
 import com.ning.billing.util.api.TagUserApi;
@@ -139,7 +139,7 @@ public class DefaultBillingApi implements BillingApi {
 
     private void addBillingEventsForSubscription(final List<Subscription> subscriptions, final SubscriptionBundle bundle, final Account account, final CallContext context, final DefaultBillingEventSet result) {
         for (final Subscription subscription : subscriptions) {
-            for (final SubscriptionEvent transition : subscription.getBillingTransitions()) {
+            for (final EffectiveSubscriptionEvent transition : subscription.getBillingTransitions()) {
                 try {
                     final int bcd = bcdCalculator.calculateBcd(bundle, subscription, transition, account);
 
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
index 284aa99..5364b18 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
@@ -31,8 +31,8 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.billing.BillingEvent;
 import com.ning.billing.entitlement.api.billing.BillingModeType;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 
 public class DefaultBillingEvent implements BillingEvent {
     private final Account account;
@@ -51,7 +51,7 @@ public class DefaultBillingEvent implements BillingEvent {
     private final Long totalOrdering;
     private final DateTimeZone timeZone;
 
-    public DefaultBillingEvent(final Account account, final SubscriptionEvent transition, final Subscription subscription, final int billCycleDay, final Currency currency, final Catalog catalog) throws CatalogApiException {
+    public DefaultBillingEvent(final Account account, final EffectiveSubscriptionEvent transition, final Subscription subscription, final int billCycleDay, final Currency currency, final Catalog catalog) throws CatalogApiException {
 
         this.account = account;
         this.billCycleDay = billCycleDay;
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java
index 2e52c0f..e82a1d6 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java
@@ -27,9 +27,9 @@ import com.ning.billing.catalog.api.PlanPhase;
 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.EffectiveSubscriptionEvent;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.util.callcontext.CallContext;
@@ -103,15 +103,15 @@ public class MockSubscription implements Subscription {
         return sub.getCategory();
     }
 
-    public SubscriptionEvent getPendingTransition() {
+    public EffectiveSubscriptionEvent getPendingTransition() {
         return sub.getPendingTransition();
     }
 
-    public SubscriptionEvent getPreviousTransition() {
+    public EffectiveSubscriptionEvent getPreviousTransition() {
         return sub.getPreviousTransition();
     }
 
-    public List<SubscriptionEvent> getBillingTransitions() {
+    public List<EffectiveSubscriptionEvent> getBillingTransitions() {
         return sub.getBillingTransitions();
     }
 
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
index ae5f680..ee83777 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
@@ -53,11 +53,11 @@ import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.billing.BillingEvent;
 import com.ning.billing.entitlement.api.billing.BillingModeType;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.junction.api.BillingApi;
 import com.ning.billing.junction.api.BillingEventSet;
 import com.ning.billing.junction.api.Blockable;
@@ -130,7 +130,7 @@ public class TestBillingApi {
 
     private CatalogService catalogService;
 
-    private List<SubscriptionEvent> subscriptionTransitions;
+    private List<EffectiveSubscriptionEvent> effectiveSubscriptionTransitions;
     private EntitlementUserApi entitlementApi;
 
     private final BlockingCalculator blockCalculator = new BlockingCalculator(null) {
@@ -164,14 +164,14 @@ public class TestBillingApi {
         bundles.add(bundle);
 
 
-        subscriptionTransitions = new LinkedList<SubscriptionEvent>();
+        effectiveSubscriptionTransitions = new LinkedList<EffectiveSubscriptionEvent>();
         final List<Subscription> subscriptions = new LinkedList<Subscription>();
 
         subscriptionStartDate = clock.getUTCNow().minusDays(3);
         subscription = new MockSubscription() {
             @Override
-            public List<SubscriptionEvent> getBillingTransitions() {
-                return subscriptionTransitions;
+            public List<EffectiveSubscriptionEvent> getBillingTransitions() {
+                return effectiveSubscriptionTransitions;
             }
 
             @Override
@@ -237,13 +237,13 @@ public class TestBillingApi {
         final PlanPhase nextPhase = nextPlan.getAllPhases()[0]; // The trial has no billing period
         final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 
-        final SubscriptionEvent t = new MockSubscriptionEvent(
+        final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
                 eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
                 nextPlan.getName(), nextPhase.getName(),
                 nextPriceList.getName(), 1L, null,
                 SubscriptionTransitionType.CREATE, 0, null);
 
-        subscriptionTransitions.add(t);
+        effectiveSubscriptionTransitions.add(t);
 
         final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
         final Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
@@ -268,13 +268,13 @@ public class TestBillingApi {
         final Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
-        final SubscriptionEvent t = new MockSubscriptionEvent(
+        final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
                 eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
                 nextPlan.getName(), nextPhase.getName(),
                 nextPriceList.getName(), 1L, null,
                 SubscriptionTransitionType.CREATE, 0, null);
 
-        subscriptionTransitions.add(t);
+        effectiveSubscriptionTransitions.add(t);
 
         final Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
         ((ZombieControl) account).addResult("getBillCycleDay", 1).addResult("getTimeZone", DateTimeZone.UTC)
@@ -302,14 +302,14 @@ public class TestBillingApi {
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 
-        final SubscriptionEvent t = new MockSubscriptionEvent(
+        final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
                 eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
                 nextPlan.getName(), nextPhase.getName(),
                 nextPriceList.getName(), 1L, null,
                 SubscriptionTransitionType.CREATE, 0, null);
 
 
-        subscriptionTransitions.add(t);
+        effectiveSubscriptionTransitions.add(t);
 
         final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
         final Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
@@ -338,13 +338,13 @@ public class TestBillingApi {
         final PlanPhase nextPhase = nextPlan.getAllPhases()[0];
         final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 
-        final SubscriptionEvent t = new MockSubscriptionEvent(
+        final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
                 eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
                 nextPlan.getName(), nextPhase.getName(),
                 nextPriceList.getName(), 1L, null,
                 SubscriptionTransitionType.CREATE, 0, null);
 
-        subscriptionTransitions.add(t);
+        effectiveSubscriptionTransitions.add(t);
 
         final Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
         ((ZombieControl) account).addResult("getBillCycleDay", 1).addResult("getTimeZone", DateTimeZone.UTC);
@@ -377,13 +377,13 @@ public class TestBillingApi {
         final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 
 
-        final SubscriptionEvent t = new MockSubscriptionEvent(
+        final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
                 eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
                 nextPlan.getName(), nextPhase.getName(),
                 nextPriceList.getName(), 1L, null,
                 SubscriptionTransitionType.CREATE, 0, null);
 
-        subscriptionTransitions.add(t);
+        effectiveSubscriptionTransitions.add(t);
 
         final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
         final Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
@@ -451,14 +451,14 @@ public class TestBillingApi {
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 
-        final SubscriptionEvent t = new MockSubscriptionEvent(
+        final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
                 eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
                 nextPlan.getName(), nextPhase.getName(),
                 nextPriceList.getName(), 1L, null,
                 SubscriptionTransitionType.CREATE, 0, null);
 
 
-        subscriptionTransitions.add(t);
+        effectiveSubscriptionTransitions.add(t);
 
         final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
         final Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
@@ -495,14 +495,14 @@ public class TestBillingApi {
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 
-        final SubscriptionEvent t = new MockSubscriptionEvent(
+        final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
                 eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
                 nextPlan.getName(), nextPhase.getName(),
                 nextPriceList.getName(), 1L, null,
                 SubscriptionTransitionType.CREATE, 0, null);
 
 
-        subscriptionTransitions.add(t);
+        effectiveSubscriptionTransitions.add(t);
 
         final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
         final Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);

overdue/pom.xml 5(+5 -0)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index 3104bae..d1b5cc0 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -56,6 +56,11 @@
             <artifactId>testng</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>com.ning.billing</groupId>
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 19923b3..c89f908 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
@@ -24,26 +24,27 @@ import java.util.List;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.ning.billing.config.NotificationConfig;
-import com.ning.billing.util.bus.dao.BusEventEntry;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
 import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
 
 public class DefaultNotificationQueue extends NotificationQueueBase {
+    private static final Logger log = LoggerFactory.getLogger(DefaultNotificationQueue.class);
 
-    protected final NotificationSqlDao dao;
-
-    public DefaultNotificationQueue(final IDBI dbi, final Clock clock, final String svcName, final String queueName, final NotificationQueueHandler handler, final NotificationConfig config) {
+    private final NotificationSqlDao dao;
 
+    public DefaultNotificationQueue(final IDBI dbi, final Clock clock, final String svcName, final String queueName,
+                                    final NotificationQueueHandler handler, final NotificationConfig config) {
         super(clock, svcName, queueName, handler, config);
         this.dao = dbi.onDemand(NotificationSqlDao.class);
     }
 
     @Override
     public int doProcessEvents() {
-
         logDebug("ENTER doProcessEvents");
         final List<Notification> notifications = getReadyNotifications();
         if (notifications.size() == 0) {
@@ -51,24 +52,22 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
             return 0;
         }
 
-        logDebug("START processing %d events at time %s", notifications.size(), clock.getUTCNow().toDate());
+        logDebug("START processing %d events at time %s", notifications.size(), getClock().getUTCNow().toDate());
 
         int result = 0;
         for (final Notification cur : notifications) {
-            nbProcessedEvents.incrementAndGet();
-            logDebug("handling notification %s, key = %s for time %s",
-                     cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
-            NotificationKey key = deserializeEvent(cur.getNotificationKeyClass(), cur.getNotificationKey()); 
-            handler.handleReadyNotification(key, cur.getEffectiveDate());
+            getNbProcessedEvents().incrementAndGet();
+            logDebug("handling notification %s, key = %s for time %s", cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
+            final NotificationKey key = deserializeEvent(cur.getNotificationKeyClass(), cur.getNotificationKey());
+            getHandler().handleReadyNotification(key, cur.getEffectiveDate());
             result++;
             clearNotification(cur);
-            logDebug("done handling notification %s, key = %s for time %s",
-                     cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
+            logDebug("done handling notification %s, key = %s for time %s", cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
         }
+
         return result;
     }
 
-
     @Override
     public void recordFutureNotification(final DateTime futureNotificationTime, final NotificationKey notificationKey) throws IOException {
         recordFutureNotificationInternal(futureNotificationTime, notificationKey, dao);
@@ -76,47 +75,50 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
 
     @Override
     public void recordFutureNotificationFromTransaction(final Transmogrifier transactionalDao,
-                                                        final DateTime futureNotificationTime, final NotificationKey notificationKey) throws IOException {
+                                                        final DateTime futureNotificationTime,
+                                                        final NotificationKey notificationKey) throws IOException {
         final NotificationSqlDao transactionalNotificationDao = transactionalDao.become(NotificationSqlDao.class);
         recordFutureNotificationInternal(futureNotificationTime, notificationKey, transactionalNotificationDao);
     }
-    
-    private void recordFutureNotificationInternal(final DateTime futureNotificationTime, final NotificationKey notificationKey, final NotificationSqlDao thisDao) throws IOException {
+
+    private void recordFutureNotificationInternal(final DateTime futureNotificationTime,
+                                                  final NotificationKey notificationKey,
+                                                  final NotificationSqlDao thisDao) throws IOException {
         final String json = objectMapper.writeValueAsString(notificationKey);
-        final Notification notification = new DefaultNotification(getFullQName(), hostname, notificationKey.getClass().getName(), json, futureNotificationTime);
+        final Notification notification = new DefaultNotification(getFullQName(), getHostname(), notificationKey.getClass().getName(), json, futureNotificationTime);
         thisDao.insertNotification(notification);
     }
 
     private void clearNotification(final Notification cleared) {
-        dao.clearNotification(cleared.getId().toString(), hostname);
+        dao.clearNotification(cleared.getId().toString(), getHostname());
     }
 
     private List<Notification> getReadyNotifications() {
-
-        final Date now = clock.getUTCNow().toDate();
-        final Date nextAvailable = clock.getUTCNow().plus(CLAIM_TIME_MS).toDate();
-
-        final List<Notification> input = dao.getReadyNotifications(now, hostname, CLAIM_TIME_MS, getFullQName());
+        final Date now = getClock().getUTCNow().toDate();
+        final Date nextAvailable = getClock().getUTCNow().plus(CLAIM_TIME_MS).toDate();
+        final List<Notification> input = dao.getReadyNotifications(now, getHostname(), CLAIM_TIME_MS, getFullQName());
 
         final List<Notification> claimedNotifications = new ArrayList<Notification>();
         for (final Notification cur : input) {
             logDebug("about to claim notification %s,  key = %s for time %s",
                      cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
-            final boolean claimed = (dao.claimNotification(hostname, nextAvailable, cur.getId().toString(), now) == 1);
+
+            final boolean claimed = (dao.claimNotification(getHostname(), nextAvailable, cur.getId().toString(), now) == 1);
             logDebug("claimed notification %s, key = %s for time %s result = %s",
-                     cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate(), Boolean.valueOf(claimed));
+                     cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate(), claimed);
+
             if (claimed) {
                 claimedNotifications.add(cur);
-                dao.insertClaimedHistory(hostname, now, cur.getId().toString());
+                dao.insertClaimedHistory(getHostname(), now, cur.getId().toString());
             }
         }
 
         for (final Notification cur : claimedNotifications) {
-            if (cur.getOwner() != null && !cur.getOwner().equals(hostname)) {
-                log.warn(String.format("NotificationQueue %s stealing notification %s from %s",
-                                       getFullQName(), cur, cur.getOwner()));
+            if (cur.getOwner() != null && !cur.getOwner().equals(getHostname())) {
+                log.warn("NotificationQueue {} stealing notification {} from {}", new Object[]{getFullQName(), cur, cur.getOwner()});
             }
         }
+
         return claimedNotifications;
     }
 
@@ -130,6 +132,5 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
     @Override
     public void removeNotificationsByKey(final NotificationKey notificationKey) {
         dao.removeNotificationsByKey(notificationKey.toString());
-
     }
 }
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 38b6e3c..fcc8c08 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
@@ -30,32 +30,26 @@ import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
 import com.ning.billing.util.queue.PersistentQueueBase;
 
-
 public abstract class NotificationQueueBase extends PersistentQueueBase implements NotificationQueue {
-
-    protected static final Logger log = LoggerFactory.getLogger(NotificationQueueBase.class);
+    private static final Logger log = LoggerFactory.getLogger(NotificationQueueBase.class);
 
     public static final int CLAIM_TIME_MS = (5 * 60 * 1000); // 5 minutes
 
     private static final String NOTIFICATION_THREAD_PREFIX = "Notification-";
     private static final int NB_THREADS = 1;
 
-
     private final String svcName;
     private final String queueName;
+    private final NotificationQueueHandler handler;
+    private final NotificationConfig config;
+    private final Clock clock;
+    private final String hostname;
 
-    protected final NotificationQueueHandler handler;
-    protected final NotificationConfig config;
-
-    protected final Clock clock;
-    protected final String hostname;
-
-    protected AtomicLong nbProcessedEvents;
+    private AtomicLong nbProcessedEvents;
 
     // Package visibility on purpose
     NotificationQueueBase(final Clock clock, final String svcName, final String queueName, final NotificationQueueHandler handler, final NotificationConfig config) {
         super(svcName, Executors.newFixedThreadPool(1, new ThreadFactory() {
-
             @Override
             public Thread newThread(final Runnable r) {
                 final Thread th = new Thread(r);
@@ -115,11 +109,26 @@ public abstract class NotificationQueueBase extends PersistentQueueBase implemen
         return queueName;
     }
 
-
     public String getFullQName() {
         return NotificationQueueServiceBase.getCompositeName(svcName, queueName);
     }
 
+    public AtomicLong getNbProcessedEvents() {
+        return nbProcessedEvents;
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    public NotificationQueueHandler getHandler() {
+        return handler;
+    }
+
+    public Clock getClock() {
+        return clock;
+    }
+
     @Override
     public abstract int doProcessEvents();
 }
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
index 540a0ae..7468c27 100644
--- a/util/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestBase.java
+++ b/util/src/main/java/com/ning/billing/util/userrequest/CompletionUserRequestBase.java
@@ -22,7 +22,7 @@ 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.SubscriptionEvent;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.invoice.api.EmptyInvoiceEvent;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.payment.api.PaymentErrorEvent;
@@ -103,7 +103,7 @@ public abstract class CompletionUserRequestBase implements CompletionUserRequest
                 onAccountChange((AccountChangeEvent) curEvent);
                 break;
             case SUBSCRIPTION_TRANSITION:
-                onSubscriptionTransition((SubscriptionEvent) curEvent);
+                onSubscriptionTransition((EffectiveSubscriptionEvent) curEvent);
                 break;
             case INVOICE_EMPTY:
                 onEmptyInvoice((EmptyInvoiceEvent) curEvent);
@@ -135,7 +135,7 @@ public abstract class CompletionUserRequestBase implements CompletionUserRequest
     }
 
     @Override
-    public void onSubscriptionTransition(final SubscriptionEvent curEvent) {
+    public void onSubscriptionTransition(final EffectiveSubscriptionEvent curEventEffective) {
     }
 
     @Override
diff --git a/util/src/test/java/com/ning/billing/api/TestApiListener.java b/util/src/test/java/com/ning/billing/api/TestApiListener.java
index 5fc23bc..45543f3 100644
--- a/util/src/test/java/com/ning/billing/api/TestApiListener.java
+++ b/util/src/test/java/com/ning/billing/api/TestApiListener.java
@@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Joiner;
 import com.google.common.eventbus.Subscribe;
 import com.ning.billing.entitlement.api.timeline.RepairEntitlementEvent;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.payment.api.PaymentErrorEvent;
 import com.ning.billing.payment.api.PaymentInfoEvent;
@@ -81,9 +81,9 @@ public class TestApiListener {
     }
 
     @Subscribe
-    public void handleEntitlementEvents(final SubscriptionEvent event) {
-        log.info(String.format("TestApiListener Got subscription event %s", event.toString()));
-        switch (event.getTransitionType()) {
+    public void handleEntitlementEvents(final EffectiveSubscriptionEvent eventEffective) {
+        log.info(String.format("TestApiListener Got subscription event %s", eventEffective.toString()));
+        switch (eventEffective.getTransitionType()) {
             case MIGRATE_ENTITLEMENT:
                 assertEqualsNicely(NextEvent.MIGRATE_ENTITLEMENT);
                 notifyIfStackEmpty();
@@ -117,7 +117,7 @@ public class TestApiListener {
                 notifyIfStackEmpty();
                 break;
             default:
-                throw new RuntimeException("Unexpected event type " + event.getRequestedTransitionTime());
+                throw new RuntimeException("Unexpected event type " + eventEffective.getRequestedTransitionTime());
         }
     }
 
diff --git a/util/src/test/java/com/ning/billing/mock/api/MockEntitlementUserApi.java b/util/src/test/java/com/ning/billing/mock/api/MockEntitlementUserApi.java
index d625137..60da96b 100644
--- a/util/src/test/java/com/ning/billing/mock/api/MockEntitlementUserApi.java
+++ b/util/src/test/java/com/ning/billing/mock/api/MockEntitlementUserApi.java
@@ -61,11 +61,6 @@ public class MockEntitlementUserApi implements EntitlementUserApi {
             }
 
             @Override
-            public DateTime getStartDate() {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
             public String getKey() {
                 return key;
             }
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 5e7d607..edb4f2e 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
@@ -19,7 +19,6 @@ package com.ning.billing.util.notificationq;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Comparator;
-import java.util.Iterator;
 import java.util.List;
 import java.util.TreeSet;
 
@@ -33,10 +32,10 @@ import com.ning.billing.util.notificationq.NotificationQueueService.Notification
 import com.ning.billing.util.queue.PersistentQueueEntryLifecycle.PersistentQueueEntryLifecycleState;
 
 public class MockNotificationQueue extends NotificationQueueBase implements NotificationQueue {
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
     private final TreeSet<Notification> notifications;
 
-    ObjectMapper objectMapper = new ObjectMapper();
-    
     public MockNotificationQueue(final Clock clock, final String svcName, final String queueName, final NotificationQueueHandler handler, final NotificationConfig config) {
         super(clock, svcName, queueName, handler, config);
         notifications = new TreeSet<Notification>(new Comparator<Notification>() {
@@ -52,18 +51,16 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
     }
 
     @Override
-    public void recordFutureNotification(final DateTime futureNotificationTime, final NotificationKey notificationKey) throws IOException  {
+    public void recordFutureNotification(final DateTime futureNotificationTime, final NotificationKey notificationKey) throws IOException {
         final String json = objectMapper.writeValueAsString(notificationKey);
-        final Notification notification = new DefaultNotification("MockQueue", hostname, notificationKey.getClass().getName(), json, futureNotificationTime);
+        final Notification notification = new DefaultNotification("MockQueue", getHostname(), notificationKey.getClass().getName(), json, futureNotificationTime);
         synchronized (notifications) {
             notifications.add(notification);
         }
     }
 
     @Override
-    public void recordFutureNotificationFromTransaction(
-            final Transmogrifier transactionalDao, final DateTime futureNotificationTime,
-            final NotificationKey notificationKey) throws IOException  {
+    public void recordFutureNotificationFromTransaction(final Transmogrifier transactionalDao, final DateTime futureNotificationTime, final NotificationKey notificationKey) throws IOException {
         recordFutureNotification(futureNotificationTime, notificationKey);
     }
 
@@ -75,23 +72,20 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
                 result.add(notification);
             }
         }
+
         return result;
     }
 
     @Override
     public int doProcessEvents() {
-
-        int result = 0;
-
+        final int result;
         final List<Notification> processedNotifications = new ArrayList<Notification>();
         final List<Notification> oldNotifications = new ArrayList<Notification>();
 
         final List<Notification> readyNotifications = new ArrayList<Notification>();
         synchronized (notifications) {
-            final Iterator<Notification> it = notifications.iterator();
-            while (it.hasNext()) {
-                final Notification cur = it.next();
-                if (cur.isAvailableForProcessing(clock.getUTCNow())) {
+            for (final Notification cur : notifications) {
+                if (cur.isAvailableForProcessing(getClock().getUTCNow())) {
                     readyNotifications.add(cur);
                 }
             }
@@ -99,15 +93,16 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
 
         result = readyNotifications.size();
         for (final Notification cur : readyNotifications) {
-            
-            
-            NotificationKey key = deserializeEvent(cur.getNotificationKeyClass(), cur.getNotificationKey()); 
-            handler.handleReadyNotification(key, cur.getEffectiveDate());
-            final DefaultNotification processedNotification = new DefaultNotification(-1L, cur.getId(), hostname, hostname, "MockQueue", clock.getUTCNow().plus(CLAIM_TIME_MS), PersistentQueueEntryLifecycleState.PROCESSED,
-                    cur.getNotificationKeyClass(), cur.getNotificationKey(), cur.getEffectiveDate());
+            final NotificationKey key = deserializeEvent(cur.getNotificationKeyClass(), cur.getNotificationKey());
+            getHandler().handleReadyNotification(key, cur.getEffectiveDate());
+            final DefaultNotification processedNotification = new DefaultNotification(-1L, cur.getId(), getHostname(), getHostname(),
+                                                                                      "MockQueue", getClock().getUTCNow().plus(CLAIM_TIME_MS),
+                                                                                      PersistentQueueEntryLifecycleState.PROCESSED, cur.getNotificationKeyClass(),
+                                                                                      cur.getNotificationKey(), cur.getEffectiveDate());
             oldNotifications.add(cur);
             processedNotifications.add(processedNotification);
         }
+
         synchronized (notifications) {
             if (oldNotifications.size() > 0) {
                 notifications.removeAll(oldNotifications);
@@ -117,6 +112,7 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
                 notifications.addAll(processedNotifications);
             }
         }
+
         return result;
     }
 
@@ -128,11 +124,11 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
                 toClearNotifications.add(notification);
             }
         }
+
         synchronized (notifications) {
             if (toClearNotifications.size() > 0) {
                 notifications.removeAll(toClearNotifications);
             }
         }
-
     }
 }