killbill-memoizeit
Changes
analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java 14(+7 -7)
analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java 18(+9 -9)
entitlement/pom.xml 5(+5 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java 44(+19 -25)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java 54(+16 -38)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java 6(+3 -3)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java 32(+13 -19)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEffectiveSubscriptionEvent.java 55(+55 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java 31(+13 -18)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java 55(+55 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java 110(+47 -63)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionEvent.java 238(+78 -160)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java 21(+13 -8)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java 72(+58 -14)
entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java 195(+89 -106)
entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java 42(+19 -23)
entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg 5(+2 -3)
junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscriptionBundle.java 48(+42 -6)
junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java 4(+2 -2)
junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockEffectiveSubscriptionEvent.java 42(+21 -21)
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);
entitlement/pom.xml 5(+5 -0)
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);
}
}
-
}
}