killbill-uncached

Changes

entitlement/src/main/java/com/ning/billing/entitlement/glue/InjectorMagic.java 76(+0 -76)

Details

diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
index 595a2ff..15442ed 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
@@ -28,17 +28,14 @@ import com.ning.billing.entitlement.api.user.SubscriptionBuilder;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
-import com.ning.billing.util.clock.Clock;
 
 public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
 
-    private final Clock clock;
     private final EntitlementDao dao;
 
     @Inject
-    public DefaultEntitlementBillingApi(Clock clock, EntitlementDao dao) {
+    public DefaultEntitlementBillingApi(EntitlementDao dao) {
         super();
-        this.clock = clock;
         this.dao = dao;
     }
 
@@ -63,7 +60,6 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         SubscriptionBuilder builder = new SubscriptionBuilder(subscription)
             .setChargedThroughDate(ctd)
             .setPaidThroughDate(subscription.getPaidThroughDate());
-        dao.updateSubscription(new SubscriptionData(builder, false));
+        dao.updateSubscription(new SubscriptionData(builder));
     }
-
 }
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 4fd2cd0..16e3de5 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
@@ -16,7 +16,6 @@
 
 package com.ning.billing.entitlement.api.user;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
@@ -31,18 +30,11 @@ import com.ning.billing.catalog.api.ICatalogService;
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
 import com.ning.billing.catalog.api.IPriceListSet;
-import com.ning.billing.catalog.api.PlanAlignmentChange;
 import com.ning.billing.entitlement.alignment.PlanAligner;
-import com.ning.billing.entitlement.alignment.TimedPhase;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
-import com.ning.billing.entitlement.events.EntitlementEvent;
-import com.ning.billing.entitlement.events.phase.PhaseEvent;
-import com.ning.billing.entitlement.events.phase.PhaseEventData;
-import com.ning.billing.entitlement.events.user.ApiEventBuilder;
-import com.ning.billing.entitlement.events.user.ApiEventCreate;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.DefaultClock;
 import com.ning.billing.util.clock.Clock;
@@ -53,12 +45,14 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
     private final EntitlementDao dao;
     private final PlanAligner planAligner;
     private final ICatalogService catalogService;
+    private final SubscriptionApiService apiService;
 
     @Inject
     public DefaultEntitlementUserApi(Clock clock, PlanAligner planAligner,
-            EntitlementDao dao, ICatalogService catalogService) {
+            EntitlementDao dao, ICatalogService catalogService, SubscriptionApiService apiService) {
         super();
         this.clock = clock;
+        this.apiService = apiService;
         this.dao = dao;
         this.planAligner = planAligner;
         this.catalogService = catalogService;
@@ -157,34 +151,14 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
         }
 
         DateTime effectiveDate = requestedDate;
-        SubscriptionData subscription = new SubscriptionData(new SubscriptionBuilder()
+        SubscriptionData subscription = apiService.create(new SubscriptionBuilder()
             .setId(UUID.randomUUID())
             .setBundleId(bundleId)
             .setCategory(plan.getProduct().getCategory())
             .setBundleStartDate(bundleStartDate)
             .setStartDate(effectiveDate),
-                false);
-
-        TimedPhase currentTimedPhase =  planAligner.getCurrentTimedPhaseOnCreate(subscription, plan, realPriceList, effectiveDate);
-        ApiEventCreate creationEvent = new ApiEventCreate(new ApiEventBuilder()
-            .setSubscriptionId(subscription.getId())
-            .setEventPlan(plan.getName())
-            .setEventPlanPhase(currentTimedPhase.getPhase().getName())
-            .setEventPriceList(realPriceList)
-            .setActiveVersion(subscription.getActiveVersion())
-            .setProcessedDate(now)
-            .setEffectiveDate(effectiveDate)
-            .setRequestedDate(requestedDate));
-
-        TimedPhase nextTimedPhase =  planAligner.getNextTimedPhaseOnCreate(subscription, plan, realPriceList, effectiveDate);
-        PhaseEvent nextPhaseEvent = PhaseEventData.getNextPhaseEvent(nextTimedPhase, subscription, now);
-        List<EntitlementEvent> events = new ArrayList<EntitlementEvent>();
-        events.add(creationEvent);
-        if (nextPhaseEvent != null) {
-            events.add(nextPhaseEvent);
-        }
+                plan, realPriceList, requestedDate, effectiveDate, now);
 
-        // STEPH Also update startDate for bundle ?
-        return dao.createSubscription(subscription, events);
+        return subscription;
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
new file mode 100644
index 0000000..334d066
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
@@ -0,0 +1,259 @@
+/*
+ * 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.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.joda.time.DateTime;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.ActionPolicy;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.ICatalogService;
+import com.ning.billing.catalog.api.IPlan;
+import com.ning.billing.catalog.api.IPriceList;
+import com.ning.billing.catalog.api.IProduct;
+import com.ning.billing.catalog.api.PlanChangeResult;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.entitlement.alignment.PlanAligner;
+import com.ning.billing.entitlement.alignment.TimedPhase;
+import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
+import com.ning.billing.entitlement.engine.dao.EntitlementDao;
+import com.ning.billing.entitlement.events.EntitlementEvent;
+import com.ning.billing.entitlement.events.phase.PhaseEvent;
+import com.ning.billing.entitlement.events.phase.PhaseEventData;
+import com.ning.billing.entitlement.events.user.ApiEventBuilder;
+import com.ning.billing.entitlement.events.user.ApiEventCancel;
+import com.ning.billing.entitlement.events.user.ApiEventChange;
+import com.ning.billing.entitlement.events.user.ApiEventCreate;
+import com.ning.billing.entitlement.events.user.ApiEventUncancel;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.DefaultClock;
+
+public class SubscriptionApiService {
+
+    private final Clock clock;
+    private final EntitlementDao dao;
+    private final ICatalogService catalogService;
+    private final PlanAligner planAligner;
+
+    @Inject
+    public SubscriptionApiService(Clock clock, EntitlementDao dao, ICatalogService catalogService, PlanAligner planAligner) {
+        this.clock = clock;
+        this.catalogService = catalogService;
+        this.planAligner = planAligner;
+        this.dao = dao;
+    }
+
+
+
+    public SubscriptionData createFromExisting(SubscriptionBuilder builder, List<EntitlementEvent> events) {
+        SubscriptionData subscription = new SubscriptionData(builder, this, clock);
+        subscription.rebuildTransitions(events, catalogService.getCatalog());
+        return subscription;
+    }
+
+    public SubscriptionData create(SubscriptionBuilder builder, IPlan plan, String realPriceList,
+            DateTime requestedDate, DateTime effectiveDate, DateTime processedDate) {
+        SubscriptionData subscription = new SubscriptionData(builder, this, clock);
+
+
+        TimedPhase currentTimedPhase =  planAligner.getCurrentTimedPhaseOnCreate(subscription, plan, realPriceList, effectiveDate);
+        ApiEventCreate creationEvent = new ApiEventCreate(new ApiEventBuilder()
+            .setSubscriptionId(subscription.getId())
+            .setEventPlan(plan.getName())
+            .setEventPlanPhase(currentTimedPhase.getPhase().getName())
+            .setEventPriceList(realPriceList)
+            .setActiveVersion(subscription.getActiveVersion())
+            .setProcessedDate(processedDate)
+            .setEffectiveDate(effectiveDate)
+            .setRequestedDate(requestedDate));
+
+        TimedPhase nextTimedPhase =  planAligner.getNextTimedPhaseOnCreate(subscription, plan, realPriceList, effectiveDate);
+        PhaseEvent nextPhaseEvent = PhaseEventData.getNextPhaseEvent(nextTimedPhase, subscription, processedDate);
+        List<EntitlementEvent> events = new ArrayList<EntitlementEvent>();
+        events.add(creationEvent);
+        if (nextPhaseEvent != null) {
+            events.add(nextPhaseEvent);
+        }
+        dao.createSubscription(subscription, events);
+        subscription.rebuildTransitions(events, catalogService.getCatalog());
+        return subscription;
+    }
+
+    public void cancel(SubscriptionData subscription, DateTime requestedDate, boolean eot)
+        throws EntitlementUserApiException {
+
+        SubscriptionState currentState = subscription.getState();
+        if (currentState != SubscriptionState.ACTIVE) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_CANCEL_BAD_STATE, subscription.getId(), currentState);
+        }
+
+        DateTime now = clock.getUTCNow();
+        requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : null;
+        if (requestedDate != null && requestedDate.isAfter(now)) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_REQUESTED_DATE, requestedDate.toString());
+        }
+
+        IPlan currentPlan = subscription.getCurrentPlan();
+        PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+                currentPlan.getProduct().getCategory(),
+                subscription.getCurrentPlan().getBillingPeriod(),
+                subscription.getCurrentPriceList(),
+                subscription.getCurrentPhase().getPhaseType());
+
+        //TODO: Correctly handle exception
+        ActionPolicy policy = null;
+        try {
+            policy = catalogService.getCatalog().planCancelPolicy(planPhase);
+        } catch (CatalogApiException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, now);
+
+        EntitlementEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
+        .setSubscriptionId(subscription.getId())
+        .setActiveVersion(subscription.getActiveVersion())
+        .setProcessedDate(now)
+        .setEffectiveDate(effectiveDate)
+        .setRequestedDate(now));
+
+        dao.cancelSubscription(subscription.getId(), cancelEvent);
+        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getCatalog());
+    }
+
+
+    public void uncancel(SubscriptionData subscription) throws EntitlementUserApiException {
+        if (!subscription.isSubscriptionFutureCancelled()) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_UNCANCEL_BAD_STATE, subscription.getId().toString());
+        }
+        DateTime now = clock.getUTCNow();
+        EntitlementEvent uncancelEvent = new ApiEventUncancel(new ApiEventBuilder()
+            .setSubscriptionId(subscription.getId())
+            .setActiveVersion(subscription.getActiveVersion())
+            .setProcessedDate(now)
+            .setRequestedDate(now)
+            .setEffectiveDate(now));
+
+        List<EntitlementEvent> uncancelEvents = new ArrayList<EntitlementEvent>();
+        uncancelEvents.add(uncancelEvent);
+
+        DateTime planStartDate = subscription.getCurrentPlanStart();
+        TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, subscription.getCurrentPlan(), now, planStartDate);
+        PhaseEvent nextPhaseEvent = PhaseEventData.getNextPhaseEvent(nextTimedPhase, subscription, now);
+        if (nextPhaseEvent != null) {
+            uncancelEvents.add(nextPhaseEvent);
+        }
+        dao.uncancelSubscription(subscription.getId(), uncancelEvents);
+        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getCatalog());
+    }
+
+    public void changePlan(SubscriptionData subscription, String productName, BillingPeriod term,
+            String priceList, DateTime requestedDate) throws EntitlementUserApiException {
+
+        requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : null;
+        String currentPriceList = subscription.getCurrentPriceList();
+
+        SubscriptionState currentState = subscription.getState();
+        if (currentState != SubscriptionState.ACTIVE) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_CHANGE_NON_ACTIVE, subscription.getId(), currentState);
+        }
+
+        if (subscription.isSubscriptionFutureCancelled()) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_CHANGE_FUTURE_CANCELLED, subscription.getId());
+        }
+
+        DateTime now = clock.getUTCNow();
+        PlanChangeResult planChangeResult = null;
+        try {
+
+            IProduct destProduct = catalogService.getCatalog().findProduct(productName);
+            // STEPH really catalog exception
+            if (destProduct == null) {
+                throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_BAD_CATALOG,
+                        productName, term.toString(), "");
+            }
+
+            IPlan currentPlan = subscription.getCurrentPlan();
+            PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+                    currentPlan.getProduct().getCategory(),
+                    currentPlan.getBillingPeriod(),
+                    currentPriceList, subscription.getCurrentPhase().getPhaseType());
+            PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
+                    destProduct.getCategory(),
+                    term,
+                    priceList);
+
+            planChangeResult = catalogService.getCatalog().planChange(fromPlanPhase, toPlanPhase);
+        } catch (CatalogApiException e) {
+            throw new EntitlementUserApiException(e);
+        }
+
+        ActionPolicy policy = planChangeResult.getPolicy();
+        IPriceList newPriceList = planChangeResult.getNewPriceList();
+
+        //TODO: Correctly handle exception
+        IPlan newPlan = null;
+        try {
+            newPlan = catalogService.getCatalog().findPlan(productName, term, newPriceList.getName());
+        } catch (CatalogApiException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        if (newPlan == null) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_BAD_CATALOG,
+                    productName, term.toString(), newPriceList.getName());
+        }
+
+        DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, now);
+
+        TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(subscription, newPlan, newPriceList.getName(), effectiveDate);
+
+        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(now));
+
+        TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, newPriceList.getName(), effectiveDate);
+        PhaseEvent nextPhaseEvent = PhaseEventData.getNextPhaseEvent(nextTimedPhase, subscription, now);
+        List<EntitlementEvent> changeEvents = new ArrayList<EntitlementEvent>();
+        // Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.
+        if (nextPhaseEvent != null && ! nextPhaseEvent.getEffectiveDate().equals(changeEvent.getEffectiveDate())) {
+            changeEvents.add(nextPhaseEvent);
+        }
+        changeEvents.add(changeEvent);
+        dao.changePlan(subscription.getId(), changeEvents);
+        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getCatalog());
+    }
+
+
+
+
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBuilder.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBuilder.java
index dbc2a5e..88646c3 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBuilder.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBuilder.java
@@ -50,6 +50,7 @@ public class SubscriptionBuilder {
         this.paidThroughDate = original.getPaidThroughDate();
     }
 
+
     public SubscriptionBuilder setId(UUID id) {
         this.id = id;
         return this;
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 1454e92..8b27f6c 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
@@ -33,40 +33,20 @@ import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.ICatalog;
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
-import com.ning.billing.catalog.api.IPriceList;
-import com.ning.billing.catalog.api.IProduct;
-import com.ning.billing.catalog.api.PlanChangeResult;
-import com.ning.billing.catalog.api.PlanPhaseSpecifier;
-import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.alignment.PlanAligner;
-import com.ning.billing.entitlement.alignment.TimedPhase;
-import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
-import com.ning.billing.entitlement.events.phase.PhaseEventData;
-import com.ning.billing.entitlement.events.user.ApiEventBuilder;
-import com.ning.billing.entitlement.events.user.ApiEventCancel;
-import com.ning.billing.entitlement.events.user.ApiEventChange;
-import com.ning.billing.entitlement.events.user.ApiEventCreate;
 import com.ning.billing.entitlement.events.user.ApiEventType;
-import com.ning.billing.entitlement.events.user.ApiEventUncancel;
 import com.ning.billing.entitlement.events.user.ApiEvent;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
-import com.ning.billing.entitlement.glue.InjectorMagic;
-import com.ning.billing.util.clock.DefaultClock;
 import com.ning.billing.util.clock.Clock;
 
 public class SubscriptionData implements Subscription {
 
-    //
-    // Singletons used to perform API changes
-    private final Clock clock;
-    private final EntitlementDao dao;
-    private final ICatalog catalog;
-    private final PlanAligner planAligner;
 
+    private final Clock clock;
+    private final SubscriptionApiService apiService;
     //
     // Final subscription fields
     //
@@ -90,12 +70,15 @@ public class SubscriptionData implements Subscription {
     //
     private List<SubscriptionTransitionData> transitions;
 
-    public SubscriptionData(SubscriptionBuilder builder, boolean rebuildTransition) {
+    // Transient object never returned at the API
+    public SubscriptionData(SubscriptionBuilder builder) {
+        this(builder, null, null);
+    }
+
+    public SubscriptionData(SubscriptionBuilder builder, SubscriptionApiService apiService, Clock clock) {
         super();
-        this.clock = InjectorMagic.getClock();
-        this.dao = InjectorMagic.getEntitlementDao();
-        this.catalog = InjectorMagic.getCatlog();
-        this.planAligner = InjectorMagic.getPlanAligner();
+        this.apiService = apiService;
+        this.clock = clock;
         this.id = builder.getId();
         this.bundleId = builder.getBundleId();
         this.startDate = builder.getStartDate();
@@ -104,9 +87,6 @@ public class SubscriptionData implements Subscription {
         this.activeVersion = builder.getActiveVersion();
         this.chargedThroughDate = builder.getChargedThroughDate();
         this.paidThroughDate = builder.getPaidThroughDate();
-        if (rebuildTransition) {
-            rebuildTransitions();
-        }
     }
 
     @Override
@@ -160,156 +140,18 @@ public class SubscriptionData implements Subscription {
 
     @Override
     public void cancel(DateTime requestedDate, boolean eot) throws EntitlementUserApiException  {
-
-        SubscriptionState currentState = getState();
-        if (currentState != SubscriptionState.ACTIVE) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_CANCEL_BAD_STATE, id, currentState);
-        }
-
-        DateTime now = clock.getUTCNow();
-        requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : null;
-        if (requestedDate != null && requestedDate.isAfter(now)) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_REQUESTED_DATE, requestedDate.toString());
-        }
-
-        IPlan currentPlan = getCurrentPlan();
-        PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                currentPlan.getProduct().getCategory(),
-        		getCurrentPlan().getBillingPeriod(),
-        		getCurrentPriceList(),
-        		getCurrentPhase().getPhaseType());
-
-        //TODO: Correctly handle exception
-        ActionPolicy policy = null;
-		try {
-			policy = catalog.planCancelPolicy(planPhase);
-		} catch (CatalogApiException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-
-        DateTime effectiveDate = getPlanChangeEffectiveDate(policy, now);
-
-        EntitlementEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
-        .setSubscriptionId(id)
-        .setActiveVersion(activeVersion)
-        .setProcessedDate(now)
-        .setEffectiveDate(effectiveDate)
-        .setRequestedDate(now));
-
-        dao.cancelSubscription(id, cancelEvent);
-        rebuildTransitions();
+        apiService.cancel(this, requestedDate, eot);
     }
 
     @Override
     public void uncancel() throws EntitlementUserApiException {
-        if (!isSubscriptionFutureCancelled()) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_UNCANCEL_BAD_STATE, id.toString());
-        }
-        DateTime now = clock.getUTCNow();
-        EntitlementEvent uncancelEvent = new ApiEventUncancel(new ApiEventBuilder()
-            .setSubscriptionId(id)
-            .setActiveVersion(activeVersion)
-            .setProcessedDate(now)
-            .setRequestedDate(now)
-            .setEffectiveDate(now));
-
-        List<EntitlementEvent> uncancelEvents = new ArrayList<EntitlementEvent>();
-        uncancelEvents.add(uncancelEvent);
-
-        DateTime planStartDate = getCurrentPlanStart();
-        TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(this, getCurrentPlan(), now, planStartDate);
-        PhaseEvent nextPhaseEvent = PhaseEventData.getNextPhaseEvent(nextTimedPhase, this, now);
-        if (nextPhaseEvent != null) {
-            uncancelEvents.add(nextPhaseEvent);
-        }
-        dao.uncancelSubscription(id, uncancelEvents);
-        rebuildTransitions();
+        apiService.uncancel(this);
     }
 
     @Override
     public void changePlan(String productName, BillingPeriod term,
             String priceList, DateTime requestedDate) throws EntitlementUserApiException {
-
-        requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : null;
-        String currentPriceList = getCurrentPriceList();
-
-        SubscriptionState currentState = getState();
-        if (currentState != SubscriptionState.ACTIVE) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_CHANGE_NON_ACTIVE, id, currentState);
-        }
-
-        if (isSubscriptionFutureCancelled()) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_CHANGE_FUTURE_CANCELLED, id);
-        }
-
-        DateTime now = clock.getUTCNow();
-        PlanChangeResult planChangeResult = null;
-        try {
-
-            IProduct destProduct = catalog.findProduct(productName);
-            // STEPH really catalog exception
-            if (destProduct == null) {
-                throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_BAD_CATALOG,
-                        productName, term.toString(), "");
-            }
-
-            IPlan currentPlan = getCurrentPlan();
-            PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                    currentPlan.getProduct().getCategory(),
-                    currentPlan.getBillingPeriod(),
-                    currentPriceList, getCurrentPhase().getPhaseType());
-            PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
-                    destProduct.getCategory(),
-                    term,
-                    priceList);
-
-            planChangeResult = catalog.planChange(fromPlanPhase, toPlanPhase);
-        } catch (CatalogApiException e) {
-            throw new EntitlementUserApiException(e);
-        }
-
-        ActionPolicy policy = planChangeResult.getPolicy();
-        IPriceList newPriceList = planChangeResult.getNewPriceList();
-
-        //TODO: Correctly handle exception
-        IPlan newPlan = null;
-		try {
-			newPlan = catalog.findPlan(productName, term, newPriceList.getName());
-		} catch (CatalogApiException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-
-		if (newPlan == null) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_BAD_CATALOG,
-                    productName, term.toString(), newPriceList.getName());
-        }
-
-        DateTime effectiveDate = getPlanChangeEffectiveDate(policy, now);
-
-        TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(this, newPlan, newPriceList.getName(), effectiveDate);
-
-        EntitlementEvent changeEvent = new ApiEventChange(new ApiEventBuilder()
-        .setSubscriptionId(id)
-        .setEventPlan(newPlan.getName())
-        .setEventPlanPhase(currentTimedPhase.getPhase().getName())
-        .setEventPriceList(newPriceList.getName())
-        .setActiveVersion(activeVersion)
-        .setProcessedDate(now)
-        .setEffectiveDate(effectiveDate)
-        .setRequestedDate(now));
-
-        TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(this, newPlan, newPriceList.getName(), effectiveDate);
-        PhaseEvent nextPhaseEvent = PhaseEventData.getNextPhaseEvent(nextTimedPhase, this, now);
-        List<EntitlementEvent> changeEvents = new ArrayList<EntitlementEvent>();
-        // Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.
-        if (nextPhaseEvent != null && ! nextPhaseEvent.getEffectiveDate().equals(changeEvent.getEffectiveDate())) {
-            changeEvents.add(nextPhaseEvent);
-        }
-        changeEvents.add(changeEvent);
-        dao.changePlan(id, changeEvents);
-        rebuildTransitions();
+        apiService.changePlan(this, productName, term, priceList, requestedDate);
     }
 
     @Override
@@ -407,7 +249,7 @@ public class SubscriptionData implements Subscription {
         return activeTransitions;
     }
 
-    private boolean isSubscriptionFutureCancelled() {
+    public boolean isSubscriptionFutureCancelled() {
         if (transitions == null) {
             return false;
         }
@@ -424,7 +266,7 @@ public class SubscriptionData implements Subscription {
     }
 
 
-    private DateTime getPlanChangeEffectiveDate(ActionPolicy policy, DateTime now) {
+    public DateTime getPlanChangeEffectiveDate(ActionPolicy policy, DateTime now) {
 
         if (policy == ActionPolicy.IMMEDIATE) {
             return now;
@@ -444,7 +286,7 @@ public class SubscriptionData implements Subscription {
     }
 
 
-    private DateTime getCurrentPhaseStart() {
+    public DateTime getCurrentPhaseStart() {
 
         if (transitions == null) {
             throw new EntitlementError(String.format("No transitions for subscription %s", getId()));
@@ -465,9 +307,8 @@ public class SubscriptionData implements Subscription {
         return transitions.get(0).getEffectiveTransitionTime();
     }
 
-    private void rebuildTransitions() {
+    public void rebuildTransitions(final List<EntitlementEvent> events, final ICatalog catalog) {
 
-        List<EntitlementEvent> events = dao.getEventsForSubscription(id);
         if (events == null) {
             return;
         }
@@ -482,8 +323,7 @@ public class SubscriptionData implements Subscription {
         String previousPhaseName = null;
         String previousPriceList = null;
 
-        this.transitions = new LinkedList<SubscriptionTransitionData>();
-
+        transitions = new LinkedList<SubscriptionTransitionData>();
         for (final EntitlementEvent cur : events) {
 
             if (!cur.isActive() || cur.getActiveVersion() < activeVersion) {
@@ -544,31 +384,42 @@ public class SubscriptionData implements Subscription {
             IPlan nextPlan = null;
             IPlanPhase nextPhase = null;
             try {
-            	previousPlan = catalog.findPlan(previousPlanName);
+                previousPlan = catalog.findPlan(previousPlanName);
             } catch (CatalogApiException e) {
-            	// TODO: handle exception
+                // TODO: handle exception
             }
             try {
-            	previousPhase = catalog.findPhase(previousPhaseName);
+                previousPhase = catalog.findPhase(previousPhaseName);
             } catch (CatalogApiException e) {
                 // TODO: handle exception
-			}
+            }
             try {
-            	nextPlan = catalog.findPlan(nextPlanName);
+                nextPlan = catalog.findPlan(nextPlanName);
             } catch (CatalogApiException e) {
-            	// TODO: handle exception
+                // TODO: handle exception
             }
             try {
-            	nextPhase = catalog.findPhase(nextPhaseName);
+                nextPhase = catalog.findPhase(nextPhaseName);
             } catch (CatalogApiException e) {
-            	// TODO: handle exception
+                // TODO: handle exception
             }
 
             SubscriptionTransitionData transition =
-                new SubscriptionTransitionData(cur.getId(), id, bundleId, cur.getType(), apiEventType,
-                        cur.getRequestedDate(), cur.getEffectiveDate(),
-                        previousState, previousPlan, previousPhase, previousPriceList,
-                        nextState, nextPlan, nextPhase, nextPriceList);
+                new SubscriptionTransitionData(cur.getId(),
+                        id,
+                        bundleId,
+                        cur.getType(),
+                        apiEventType,
+                        cur.getRequestedDate(),
+                        cur.getEffectiveDate(),
+                        previousState,
+                        previousPlan,
+                        previousPhase,
+                        previousPriceList,
+                        nextState,
+                        nextPlan,
+                        nextPhase,
+                        nextPriceList);
             transitions.add(transition);
 
             previousState = nextState;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
index 6bfccc3..835da51 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
@@ -61,7 +61,7 @@ public interface EntitlementDao {
     public void clearEventsReady(UUID ownerId, Collection<EntitlementEvent> cleared);
 
     // Subscription creation, cancellation, changePlan apis
-    public Subscription createSubscription(SubscriptionData subscription, List<EntitlementEvent> initialEvents);
+    public void createSubscription(SubscriptionData subscription, List<EntitlementEvent> initialEvents);
 
     public void cancelSubscription(UUID subscriptionId, EntitlementEvent cancelEvent);
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
index 88410a2..7f80704 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
@@ -20,7 +20,6 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
@@ -30,11 +29,12 @@ import org.skife.jdbi.v2.TransactionStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.Lists;
 import com.google.inject.Inject;
+import com.ning.billing.catalog.api.ICatalogService;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.config.EntitlementConfig;
 import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionApiService;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.api.user.SubscriptionBuilder;
@@ -51,6 +51,7 @@ public class EntitlementSqlDao implements EntitlementDao {
 
     private final static Logger log = LoggerFactory.getLogger(EntitlementSqlDao.class);
 
+    private final SubscriptionApiService apiService;
     private final Clock clock;
     private final SubscriptionSqlDao subscriptionsDao;
     private final BundleSqlDao bundlesDao;
@@ -59,9 +60,10 @@ public class EntitlementSqlDao implements EntitlementDao {
     private final String hostname;
 
     @Inject
-    public EntitlementSqlDao(DBI dbi, Clock clock, EntitlementConfig config) {
+    public EntitlementSqlDao(DBI dbi, Clock clock, EntitlementConfig config, SubscriptionApiService apiService) {
         this.clock = clock;
         this.config = config;
+        this.apiService = apiService;
         this.subscriptionsDao = dbi.onDemand(SubscriptionSqlDao.class);
         this.eventsDao = dbi.onDemand(EventSqlDao.class);
         this.bundlesDao = dbi.onDemand(BundleSqlDao.class);
@@ -87,7 +89,7 @@ public class EntitlementSqlDao implements EntitlementDao {
 
     @Override
     public Subscription getSubscriptionFromId(UUID subscriptionId) {
-        return subscriptionsDao.getSubscriptionFromId(subscriptionId.toString());
+        return buildSubscription(subscriptionsDao.getSubscriptionFromId(subscriptionId.toString()));
     }
 
     @Override
@@ -96,7 +98,7 @@ public class EntitlementSqlDao implements EntitlementDao {
         List<Subscription> subscriptions = subscriptionsDao.getSubscriptionsFromBundleId(bundleId.toString());
         for (Subscription cur : subscriptions) {
             if (((SubscriptionData)cur).getCategory() == ProductCategory.BASE) {
-                return cur;
+                return  buildSubscription(cur);
             }
         }
         return null;
@@ -104,7 +106,7 @@ public class EntitlementSqlDao implements EntitlementDao {
 
     @Override
     public List<Subscription> getSubscriptions(UUID bundleId) {
-        return subscriptionsDao.getSubscriptionsFromBundleId(bundleId.toString());
+        return buildSubscription(subscriptionsDao.getSubscriptionsFromBundleId(bundleId.toString()));
     }
 
     @Override
@@ -113,7 +115,7 @@ public class EntitlementSqlDao implements EntitlementDao {
         if (bundle == null) {
             return Collections.emptyList();
         }
-        return subscriptionsDao.getSubscriptionsFromBundleId(bundle.getId().toString());
+        return buildSubscription(subscriptionsDao.getSubscriptionsFromBundleId(bundle.getId().toString()));
     }
 
     @Override
@@ -208,7 +210,7 @@ public class EntitlementSqlDao implements EntitlementDao {
     }
 
     @Override
-    public Subscription createSubscription(final SubscriptionData subscription,
+    public void createSubscription(final SubscriptionData subscription,
             final List<EntitlementEvent> initialEvents) {
 
         subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
@@ -226,7 +228,6 @@ public class EntitlementSqlDao implements EntitlementDao {
                 return null;
             }
         });
-        return new SubscriptionData(new SubscriptionBuilder(subscription), true);
     }
 
     @Override
@@ -322,4 +323,21 @@ public class EntitlementSqlDao implements EntitlementDao {
             dao.unactiveEvent(futureEventId.toString(), now);
         }
     }
+
+    private Subscription buildSubscription(Subscription input) {
+        if (input == null) {
+            return null;
+        }
+        return buildSubscription(Collections.singletonList(input)).get(0);
+    }
+
+    private List<Subscription> buildSubscription(List<Subscription> input) {
+        List<Subscription> result = new ArrayList<Subscription>(input.size());
+        for (Subscription cur : input) {
+            List<EntitlementEvent> events = eventsDao.getEventsForSubscription(cur.getId().toString());
+            Subscription reloaded = apiService.createFromExisting(new SubscriptionBuilder((SubscriptionData) cur), events);
+            result.add(reloaded);
+        }
+        return result;
+    }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
index 94d8544..79c9f49 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
@@ -108,8 +108,7 @@ public interface SubscriptionSqlDao extends Transactional<SubscriptionSqlDao>, C
             .setStartDate(startDate)
             .setActiveVersion(activeVersion)
             .setChargedThroughDate(ctd)
-            .setPaidThroughDate(ptd),
-                true);
+            .setPaidThroughDate(ptd));
             return subscription;
         }
     }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
index 334de2d..4284181 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
@@ -28,6 +28,7 @@ import com.ning.billing.entitlement.api.test.DefaultEntitlementTestApi;
 import com.ning.billing.entitlement.api.test.EntitlementTestApi;
 import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.SubscriptionApiService;
 import com.ning.billing.entitlement.engine.core.DefaultApiEventProcessor;
 import com.ning.billing.entitlement.engine.core.Engine;
 import com.ning.billing.entitlement.engine.core.EventNotifier;
@@ -59,6 +60,7 @@ public class EntitlementModule extends AbstractModule {
     }
 
     protected void installEntitlementCore() {
+        bind(SubscriptionApiService.class).asEagerSingleton();
         bind(EntitlementService.class).to(Engine.class).asEagerSingleton();
         bind(Engine.class).asEagerSingleton();
         bind(PlanAligner.class).asEagerSingleton();
@@ -67,13 +69,8 @@ public class EntitlementModule extends AbstractModule {
         bind(EntitlementBillingApi.class).to(DefaultEntitlementBillingApi.class).asEagerSingleton();
     }
 
-    protected void installInjectorMagic() {
-        bind(InjectorMagic.class).asEagerSingleton();
-    }
-
     @Override
     protected void configure() {
-        installInjectorMagic();
         installConfig();
         installClock();
         installApiEventProcessor();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
index 477075b..80e4904 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
@@ -32,7 +32,6 @@ import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.events.user.ApiEvent;
-import com.ning.billing.entitlement.glue.InjectorMagic;
 import com.ning.billing.lifecycle.KillbillService.ServiceException;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.clock.Clock;
@@ -50,7 +49,6 @@ import org.testng.annotations.BeforeMethod;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.net.URL;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
@@ -92,7 +90,6 @@ public abstract class TestUserApiBase {
     @AfterClass(groups={"setup"})
     public void tearDown() {
         try {
-            InjectorMagic.instance = null;
             busService.getEventBus().register(testListener);
             ((DefaultEventBusService) busService).stopBus();
         } catch (Exception e) {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
index c9e1385..c799dfc 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
@@ -30,10 +30,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
+import com.ning.billing.catalog.api.ICatalog;
+import com.ning.billing.catalog.api.ICatalogService;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.catalog.api.TimeUnit;
 import com.ning.billing.config.EntitlementConfig;
 import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionApiService;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.api.user.SubscriptionBuilder;
@@ -54,14 +57,16 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
     private final TreeSet<EntitlementEvent> events;
     private final Clock clock;
     private final EntitlementConfig config;
+    private final SubscriptionApiService apiService;
 
 
 
     @Inject
-    public MockEntitlementDaoMemory(Clock clock, EntitlementConfig config) {
+    public MockEntitlementDaoMemory(Clock clock, EntitlementConfig config, SubscriptionApiService apiService) {
         super();
         this.clock = clock;
         this.config = config;
+        this.apiService = apiService;
         this.bundles = new ArrayList<SubscriptionBundle>();
         this.subscriptions = new ArrayList<Subscription>();
         this.events = new TreeSet<EntitlementEvent>();
@@ -124,14 +129,13 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
 
 
     @Override
-    public Subscription createSubscription(SubscriptionData subscription, List<EntitlementEvent> initalEvents) {
+    public void createSubscription(SubscriptionData subscription, List<EntitlementEvent> initalEvents) {
 
         synchronized(events) {
             events.addAll(initalEvents);
         }
         Subscription updatedSubscription = buildSubscription(subscription);
         subscriptions.add(updatedSubscription);
-        return updatedSubscription;
     }
 
     @Override
@@ -228,7 +232,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
     }
 
     private Subscription buildSubscription(SubscriptionData in) {
-        return new SubscriptionData(new SubscriptionBuilder(in), true);
+        return apiService.createFromExisting(new SubscriptionBuilder(in), getEventsForSubscription(in.getId()));
     }
 
     @Override
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
index 18896e9..118174b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
@@ -24,7 +24,10 @@ import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
 import com.google.inject.Inject;
+import com.ning.billing.catalog.api.ICatalog;
+import com.ning.billing.catalog.api.ICatalogService;
 import com.ning.billing.config.EntitlementConfig;
+import com.ning.billing.entitlement.api.user.SubscriptionApiService;
 import com.ning.billing.util.clock.Clock;
 
 public class MockEntitlementDaoSql extends EntitlementSqlDao implements MockEntitlementDao {
@@ -32,8 +35,8 @@ public class MockEntitlementDaoSql extends EntitlementSqlDao implements MockEnti
     private final ResetSqlDao resetDao;
 
     @Inject
-    public MockEntitlementDaoSql(DBI dbi, Clock clock, EntitlementConfig config) {
-        super(dbi, clock, config);
+    public MockEntitlementDaoSql(DBI dbi, Clock clock, EntitlementConfig config, SubscriptionApiService apiService ) {
+        super(dbi, clock, config, apiService);
         this.resetDao = dbi.onDemand(ResetSqlDao.class);
     }