killbill-memoizeit
Changes
analytics/pom.xml 1(+0 -1)
analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java 224(+165 -59)
analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java 12(+11 -1)
analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java 31(+16 -15)
analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java 12(+6 -6)
analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java 6(+3 -3)
analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg 85(+85 -0)
analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java 52(+52 -0)
analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java 5(+2 -3)
analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java 7(+2 -5)
analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java 41(+16 -25)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java 3(+2 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java 2(+1 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java 6(+6 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java 8(+4 -4)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java 141(+119 -22)
entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java 61(+54 -7)
entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java 15(+8 -7)
entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java 20(+10 -10)
Details
analytics/pom.xml 1(+0 -1)
diff --git a/analytics/pom.xml b/analytics/pom.xml
index ecd27bf..c95818d 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -117,7 +117,6 @@
<dependency>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-util</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
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 87a7060..bcddd64 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
@@ -24,6 +24,7 @@ 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.RequestedSubscriptionEvent;
import com.ning.billing.invoice.api.EmptyInvoiceEvent;
import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.payment.api.PaymentErrorEvent;
@@ -55,32 +56,19 @@ public class AnalyticsListener {
}
@Subscribe
- 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(eventEffective);
- break;
- case RE_CREATE:
- bstRecorder.subscriptionRecreated(eventEffective);
- break;
- case MIGRATE_BILLING:
- break;
- case CANCEL:
- bstRecorder.subscriptionCancelled(eventEffective);
- break;
- case CHANGE:
- bstRecorder.subscriptionChanged(eventEffective);
- break;
- case UNCANCEL:
- break;
- case PHASE:
- bstRecorder.subscriptionPhaseChanged(eventEffective);
- break;
- default:
- throw new RuntimeException("Unexpected event type " + eventEffective.getTransitionType());
- }
+ public void handleEffectiveSubscriptionTransitionChange(final EffectiveSubscriptionEvent eventEffective) throws AccountApiException, EntitlementUserApiException {
+ bstRecorder.rebuildTransitionsForBundle(eventEffective.getBundleId());
+ }
+
+ @Subscribe
+ public void handleRequestedSubscriptionTransitionChange(final RequestedSubscriptionEvent eventRequested) throws AccountApiException, EntitlementUserApiException {
+ bstRecorder.rebuildTransitionsForBundle(eventRequested.getBundleId());
+ }
+
+ @Subscribe
+ public void handleRepairEntitlement(final RepairEntitlementEvent event) {
+ // In case of repair, just rebuild all transitions
+ bstRecorder.rebuildTransitionsForBundle(event.getBundleId());
}
@Subscribe
@@ -99,6 +87,7 @@ public class AnalyticsListener {
@Subscribe
public void handleInvoiceCreation(final InvoiceCreationEvent event) {
+ // TODO - follow same logic as entitlements to support repair
invoiceRecorder.invoiceCreated(event.getInvoiceId());
}
@@ -156,9 +145,4 @@ public class AnalyticsListener {
public void handleUserTagDefinitionDeletion(final UserTagDefinitionDeletionEvent event) {
// Ignored for now
}
-
- @Subscribe
- public void handleRepairEntitlement(final RepairEntitlementEvent event) {
- // Ignored for now
- }
}
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 49d6a9d..a4c9ff3 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
@@ -16,9 +16,13 @@
package com.ning.billing.analytics;
+import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
import org.joda.time.DateTime;
+import org.skife.jdbi.v2.Transaction;
+import org.skife.jdbi.v2.TransactionStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,10 +36,14 @@ 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.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;
+import com.ning.billing.util.clock.Clock;
public class BusinessSubscriptionTransitionRecorder {
private static final Logger log = LoggerFactory.getLogger(BusinessSubscriptionTransitionRecorder.class);
@@ -44,94 +52,194 @@ public class BusinessSubscriptionTransitionRecorder {
private final EntitlementUserApi entitlementApi;
private final AccountUserApi accountApi;
private final CatalogService catalogService;
+ private final Clock clock;
@Inject
- public BusinessSubscriptionTransitionRecorder(final BusinessSubscriptionTransitionSqlDao sqlDao, final CatalogService catalogService, final EntitlementUserApi entitlementApi, final AccountUserApi accountApi) {
+ public BusinessSubscriptionTransitionRecorder(final BusinessSubscriptionTransitionSqlDao sqlDao,
+ final CatalogService catalogService,
+ final EntitlementUserApi entitlementApi,
+ final AccountUserApi accountApi,
+ final Clock clock) {
this.sqlDao = sqlDao;
this.catalogService = catalogService;
this.entitlementApi = entitlementApi;
this.accountApi = accountApi;
+ this.clock = clock;
}
+ public void rebuildTransitionsForBundle(final UUID bundleId) {
+ final SubscriptionBundle bundle;
+ try {
+ bundle = entitlementApi.getBundleFromId(bundleId);
+ } catch (EntitlementUserApiException e) {
+ log.warn("Ignoring update for bundle {}: bundle does not exist", bundleId);
+ return;
+ }
+
+ final Account account;
+ try {
+ account = accountApi.getAccountById(bundle.getAccountId());
+ } catch (AccountApiException e) {
+ log.warn("Ignoring update for bundle {}: account {} does not exist", bundleId, bundle.getAccountId());
+ return;
+ }
+
+ final List<Subscription> subscriptions = entitlementApi.getSubscriptionsForBundle(bundleId);
+
+ final String externalKey = bundle.getKey();
+ final String accountKey = account.getExternalKey();
+ final Currency currency = account.getCurrency();
+
+ sqlDao.inTransaction(new Transaction<Void, BusinessSubscriptionTransitionSqlDao>() {
+ @Override
+ public Void inTransaction(final BusinessSubscriptionTransitionSqlDao transactional, final TransactionStatus status) throws Exception {
+ log.info("Started rebuilding transitions for bundle {}", externalKey);
+ transactional.deleteTransitionsForBundle(externalKey);
+
+ final ArrayList<BusinessSubscriptionTransition> transitions = new ArrayList<BusinessSubscriptionTransition>();
+ for (final Subscription subscription : subscriptions) {
+ for (final EffectiveSubscriptionEvent event : subscription.getAllTransitions()) {
+ final BusinessSubscriptionEvent businessEvent = getBusinessSubscriptionFromEvent(event);
+ if (businessEvent == null) {
+ continue;
+ }
+
+ final BusinessSubscription prevSubscription = createPreviousBusinessSubscription(event, businessEvent, transitions, currency);
+ final BusinessSubscription nextSubscription = createNextBusinessSubscription(event, businessEvent, currency);
+ final BusinessSubscriptionTransition transition = new BusinessSubscriptionTransition(
+ event.getTotalOrdering(),
+ externalKey,
+ accountKey,
+ event.getRequestedTransitionTime(),
+ businessEvent,
+ prevSubscription,
+ nextSubscription
+ );
- 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);
+ transactional.createTransition(transition);
+ transitions.add(transition);
+ log.info("Adding transition {}", transition);
+
+ // We need to manually add the system cancel event
+ if (SubscriptionTransitionType.CANCEL.equals(event.getTransitionType()) &&
+ clock.getUTCNow().isAfter(event.getEffectiveTransitionTime())) {
+ final BusinessSubscriptionTransition systemCancelTransition = new BusinessSubscriptionTransition(
+ event.getTotalOrdering(),
+ externalKey,
+ accountKey,
+ event.getRequestedTransitionTime(),
+ new BusinessSubscriptionEvent(BusinessSubscriptionEvent.EventType.SYSTEM_CANCEL, businessEvent.getCategory()),
+ prevSubscription,
+ nextSubscription
+ );
+ transactional.createTransition(systemCancelTransition);
+ transitions.add(systemCancelTransition);
+ log.info("Adding transition {}", systemCancelTransition);
+ }
+ }
+ }
+
+ log.info("Finished rebuilding transitions for bundle {}", externalKey);
+ return null;
+ }
+ });
}
+ private BusinessSubscriptionEvent getBusinessSubscriptionFromEvent(final SubscriptionEvent event) throws AccountApiException, EntitlementUserApiException {
+ switch (event.getTransitionType()) {
+ // A subscription enters either through migration or as newly created subscription
+ case MIGRATE_ENTITLEMENT:
+ case CREATE:
+ return subscriptionCreated(event);
+ case RE_CREATE:
+ return subscriptionRecreated(event);
+ case CANCEL:
+ return subscriptionCancelled(event);
+ case CHANGE:
+ return subscriptionChanged(event);
+ case PHASE:
+ return subscriptionPhaseChanged(event);
+ // TODO - should we really ignore these?
+ case MIGRATE_BILLING:
+ case UNCANCEL:
+ return null;
+ default:
+ log.warn("Unexpected event type " + event.getTransitionType());
+ return null;
+ }
+ }
- 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);
+ private BusinessSubscriptionEvent subscriptionCreated(final SubscriptionEvent created) throws AccountApiException, EntitlementUserApiException {
+ return BusinessSubscriptionEvent.subscriptionCreated(created.getNextPlan(), catalogService.getFullCatalog(), created.getEffectiveTransitionTime(), created.getSubscriptionStartDate());
}
+ private BusinessSubscriptionEvent subscriptionRecreated(final SubscriptionEvent recreated) throws AccountApiException, EntitlementUserApiException {
+ return BusinessSubscriptionEvent.subscriptionRecreated(recreated.getNextPlan(), catalogService.getFullCatalog(), recreated.getEffectiveTransitionTime(), recreated.getSubscriptionStartDate());
+ }
- public void subscriptionCancelled(final EffectiveSubscriptionEvent cancelled) throws AccountApiException, EntitlementUserApiException {
+ private BusinessSubscriptionEvent subscriptionCancelled(final SubscriptionEvent 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);
+ return BusinessSubscriptionEvent.subscriptionCancelled(cancelled.getPreviousPlan(), catalogService.getFullCatalog(), cancelled.getEffectiveTransitionTime(), cancelled.getSubscriptionStartDate());
}
+ private BusinessSubscriptionEvent subscriptionChanged(final SubscriptionEvent changed) throws AccountApiException, EntitlementUserApiException {
+ return BusinessSubscriptionEvent.subscriptionChanged(changed.getNextPlan(), catalogService.getFullCatalog(), changed.getEffectiveTransitionTime(), changed.getSubscriptionStartDate());
+ }
- 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);
+ private BusinessSubscriptionEvent subscriptionPhaseChanged(final SubscriptionEvent phaseChanged) throws AccountApiException, EntitlementUserApiException {
+ return BusinessSubscriptionEvent.subscriptionPhaseChanged(phaseChanged.getNextPlan(), phaseChanged.getNextState(), catalogService.getFullCatalog(), phaseChanged.getEffectiveTransitionTime(), phaseChanged.getSubscriptionStartDate());
}
- 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);
+ private BusinessSubscription createNextBusinessSubscription(final EffectiveSubscriptionEvent event, final BusinessSubscriptionEvent businessEvent, final Currency currency) {
+ final BusinessSubscription nextSubscription;
+ if (BusinessSubscriptionEvent.EventType.CANCEL.equals(businessEvent.getEventType()) ||
+ BusinessSubscriptionEvent.EventType.SYSTEM_CANCEL.equals(businessEvent.getEventType())) {
+ nextSubscription = null;
+ } else {
+ nextSubscription = new BusinessSubscription(event.getNextPriceList(), event.getNextPlan(), event.getNextPhase(),
+ currency, event.getEffectiveTransitionTime(), event.getNextState(),
+ event.getSubscriptionId(), event.getBundleId(), catalogService.getFullCatalog());
+ }
+
+ return nextSubscription;
}
- void recordTransition(final BusinessSubscriptionEvent event, final EffectiveSubscriptionEvent transition)
- throws AccountApiException, EntitlementUserApiException {
- Currency currency = null;
- String externalKey = null;
- String accountKey = null;
-
- // Retrieve key and currency via the bundle
- final SubscriptionBundle bundle = entitlementApi.getBundleFromId(transition.getBundleId());
- if (bundle != null) {
- externalKey = bundle.getKey();
-
- final Account account = accountApi.getAccountById(bundle.getAccountId());
- if (account != null) {
- accountKey = account.getExternalKey();
- currency = account.getCurrency();
- }
+ private BusinessSubscription createPreviousBusinessSubscription(final EffectiveSubscriptionEvent event,
+ final BusinessSubscriptionEvent businessEvent,
+ final ArrayList<BusinessSubscriptionTransition> transitions,
+ final Currency currency) {
+ if (BusinessSubscriptionEvent.EventType.ADD.equals(businessEvent.getEventType()) ||
+ BusinessSubscriptionEvent.EventType.RE_ADD.equals(businessEvent.getEventType())) {
+ return null;
}
- // The ISubscriptionTransition interface gives us all the prev/next information we need but the start date
- // of the previous plan. We need to retrieve it from our own transitions table
- DateTime previousEffectiveTransitionTime = null;
- // For creation events, the prev subscription will always be null
- if (event.getEventType() != BusinessSubscriptionEvent.EventType.ADD) {
- final List<BusinessSubscriptionTransition> transitions = sqlDao.getTransitions(externalKey);
- if (transitions != null && transitions.size() > 0) {
- final BusinessSubscriptionTransition lastTransition = transitions.get(transitions.size() - 1);
- if (lastTransition != null && lastTransition.getNextSubscription() != null) {
- previousEffectiveTransitionTime = lastTransition.getNextSubscription().getStartDate();
- }
+ final BusinessSubscriptionTransition prevTransition = getPreviousBusinessSubscriptionTransitionForEvent(event, transitions);
+ return new BusinessSubscription(event.getPreviousPriceList(), event.getPreviousPlan(), event.getPreviousPhase(),
+ currency, prevTransition.getNextSubscription().getStartDate(), event.getPreviousState(),
+ event.getSubscriptionId(), event.getBundleId(), catalogService.getFullCatalog());
+ }
+
+ private BusinessSubscriptionTransition getPreviousBusinessSubscriptionTransitionForEvent(final EffectiveSubscriptionEvent event,
+ final ArrayList<BusinessSubscriptionTransition> transitions) {
+ BusinessSubscriptionTransition transition = null;
+ for (final BusinessSubscriptionTransition candidate : transitions) {
+ final BusinessSubscription nextSubscription = candidate.getNextSubscription();
+ if (nextSubscription == null || !nextSubscription.getStartDate().isBefore(event.getEffectiveTransitionTime())) {
+ continue;
}
- }
- // TODO Support currency changes
- final BusinessSubscription prevSubscription;
- if (previousEffectiveTransitionTime == null) {
- prevSubscription = null;
- } else {
- prevSubscription = new BusinessSubscription(transition.getPreviousPriceList(), transition.getPreviousPlan(), transition.getPreviousPhase(), currency, previousEffectiveTransitionTime, transition.getPreviousState(), transition.getSubscriptionId(), transition.getBundleId(), catalogService.getFullCatalog());
+ if (nextSubscription.getSubscriptionId().equals(event.getSubscriptionId())) {
+ transition = candidate;
+ }
}
- final BusinessSubscription nextSubscription;
- // next plan is null for CANCEL events
- if (transition.getNextPlan() == null) {
- nextSubscription = null;
- } else {
- nextSubscription = new BusinessSubscription(transition.getNextPriceList(), transition.getNextPlan(), transition.getNextPhase(), currency, transition.getEffectiveTransitionTime(), transition.getNextState(), transition.getSubscriptionId(), transition.getBundleId(), catalogService.getFullCatalog());
+ if (transition == null) {
+ log.error("Unable to retrieve the previous transition - THIS SHOULD NEVER HAPPEN");
+ // Fall back to the latest one?
+ transition = transitions.get(transitions.size() - 1);
}
- record(transition.getTotalOrdering(), externalKey, accountKey, transition.getRequestedTransitionTime(), event, prevSubscription, nextSubscription);
+ return transition;
}
// Public for internal reasons
@@ -145,8 +253,6 @@ public class BusinessSubscriptionTransitionRecorder {
prevSubscription,
nextSubscription
);
-
- log.info(transition.getEvent() + " " + transition);
sqlDao.createTransition(transition);
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
index fe90321..2092d47 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
@@ -22,19 +22,29 @@ import org.skife.jdbi.v2.sqlobject.Bind;
import org.skife.jdbi.v2.sqlobject.SqlQuery;
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper(BusinessSubscriptionTransitionMapper.class)
-public interface BusinessSubscriptionTransitionSqlDao {
+public interface BusinessSubscriptionTransitionSqlDao extends Transactional<BusinessSubscriptionTransitionSqlDao> {
@SqlQuery
List<BusinessSubscriptionTransition> getTransitions(@Bind("external_key") final String externalKey);
+ @SqlQuery
+ List<BusinessSubscriptionTransition> getTransitionForSubscription(@Bind("subscription_id") final String subscriptionId);
+
@SqlUpdate
int createTransition(@BusinessSubscriptionTransitionBinder final BusinessSubscriptionTransition transition);
@SqlUpdate
+ void updateTransition(@Bind("total_ordering") long totalOrdering, @BusinessSubscriptionTransitionBinder BusinessSubscriptionTransition updatedFirstTransition);
+
+ @SqlUpdate
+ void deleteTransitionsForBundle(@Bind("external_key") final String externalKey);
+
+ @SqlUpdate
void test();
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountField.java
index b990125..3d9df23 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountField.java
@@ -33,8 +33,8 @@ public class BusinessAccountField extends BusinessField {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessAccountField");
sb.append("{accountKey='").append(accountKey).append('\'');
- sb.append(", name='").append(name).append('\'');
- sb.append(", value='").append(value).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
+ sb.append(", value='").append(getValue()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -53,10 +53,10 @@ public class BusinessAccountField extends BusinessField {
if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- if (value != null ? !value.equals(that.value) : that.value != null) {
+ if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) {
return false;
}
@@ -66,8 +66,8 @@ public class BusinessAccountField extends BusinessField {
@Override
public int hashCode() {
int result = accountKey != null ? accountKey.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountTag.java
index 3a8de99..1461c6d 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountTag.java
@@ -33,7 +33,7 @@ public class BusinessAccountTag extends BusinessTag {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessAccountTag");
sb.append("{accountKey='").append(accountKey).append('\'');
- sb.append(", name='").append(name).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -52,7 +52,7 @@ public class BusinessAccountTag extends BusinessTag {
if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
@@ -62,7 +62,7 @@ public class BusinessAccountTag extends BusinessTag {
@Override
public int hashCode() {
int result = accountKey != null ? accountKey.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessField.java
index 68552d0..5d5e727 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessField.java
@@ -17,8 +17,8 @@
package com.ning.billing.analytics.model;
public abstract class BusinessField {
- protected final String name;
- protected final String value;
+ private final String name;
+ private final String value;
public BusinessField(final String name, final String value) {
this.name = name;
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceField.java
index cf69497..d4597f4 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceField.java
@@ -35,8 +35,8 @@ public class BusinessInvoiceField extends BusinessField {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessInvoiceField");
sb.append("{invoiceId='").append(invoiceId).append('\'');
- sb.append(", name='").append(name).append('\'');
- sb.append(", value='").append(value).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
+ sb.append(", value='").append(getValue()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -55,10 +55,10 @@ public class BusinessInvoiceField extends BusinessField {
if (invoiceId != null ? !invoiceId.equals(that.invoiceId) : that.invoiceId != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- if (value != null ? !value.equals(that.value) : that.value != null) {
+ if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) {
return false;
}
@@ -68,8 +68,8 @@ public class BusinessInvoiceField extends BusinessField {
@Override
public int hashCode() {
int result = invoiceId != null ? invoiceId.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentField.java
index bcfc85b..c79b2b1 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentField.java
@@ -35,8 +35,8 @@ public class BusinessInvoicePaymentField extends BusinessField {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessPaymentField");
sb.append("{paymentId='").append(paymentId).append('\'');
- sb.append(", name='").append(name).append('\'');
- sb.append(", value='").append(value).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
+ sb.append(", value='").append(getValue()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -55,10 +55,10 @@ public class BusinessInvoicePaymentField extends BusinessField {
if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- if (value != null ? !value.equals(that.value) : that.value != null) {
+ if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) {
return false;
}
@@ -68,8 +68,8 @@ public class BusinessInvoicePaymentField extends BusinessField {
@Override
public int hashCode() {
int result = paymentId != null ? paymentId.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentTag.java
index fd48b1c..e1cbbd5 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentTag.java
@@ -35,7 +35,7 @@ public class BusinessInvoicePaymentTag extends BusinessTag {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessPaymentTag");
sb.append("{paymentId='").append(paymentId).append('\'');
- sb.append(", name='").append(name).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -54,7 +54,7 @@ public class BusinessInvoicePaymentTag extends BusinessTag {
if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
@@ -64,7 +64,7 @@ public class BusinessInvoicePaymentTag extends BusinessTag {
@Override
public int hashCode() {
int result = paymentId != null ? paymentId.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceTag.java
index e9efe5a..41b7d27 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceTag.java
@@ -35,7 +35,7 @@ public class BusinessInvoiceTag extends BusinessTag {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessInvoiceTag");
sb.append("{paymentId='").append(invoiceId).append('\'');
- sb.append(", name='").append(name).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -54,7 +54,7 @@ public class BusinessInvoiceTag extends BusinessTag {
if (invoiceId != null ? !invoiceId.equals(that.invoiceId) : that.invoiceId != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
@@ -64,7 +64,7 @@ public class BusinessInvoiceTag extends BusinessTag {
@Override
public int hashCode() {
int result = invoiceId != null ? invoiceId.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java
index 3618b7d..2e2a6ce 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java
@@ -112,15 +112,28 @@ public class BusinessSubscriptionTransition {
final BusinessSubscriptionTransition that = (BusinessSubscriptionTransition) o;
+ return totalOrdering == that.totalOrdering && isDuplicateOf(that);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (totalOrdering ^ (totalOrdering >>> 32));
+ result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0);
+ result = 31 * result + (accountKey != null ? accountKey.hashCode() : 0);
+ result = 31 * result + (requestedTimestamp != null ? requestedTimestamp.hashCode() : 0);
+ result = 31 * result + (event != null ? event.hashCode() : 0);
+ result = 31 * result + (previousSubscription != null ? previousSubscription.hashCode() : 0);
+ result = 31 * result + (nextSubscription != null ? nextSubscription.hashCode() : 0);
+ return result;
+ }
+
+ public boolean isDuplicateOf(final BusinessSubscriptionTransition that) {
if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
return false;
}
if (event != null ? !event.equals(that.event) : that.event != null) {
return false;
}
- if (totalOrdering != that.totalOrdering) {
- return false;
- }
if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
return false;
}
@@ -136,16 +149,4 @@ public class BusinessSubscriptionTransition {
return true;
}
-
- @Override
- public int hashCode() {
- int result = (int) (totalOrdering ^ (totalOrdering >>> 32));
- result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0);
- result = 31 * result + (accountKey != null ? accountKey.hashCode() : 0);
- result = 31 * result + (requestedTimestamp != null ? requestedTimestamp.hashCode() : 0);
- result = 31 * result + (event != null ? event.hashCode() : 0);
- result = 31 * result + (previousSubscription != null ? previousSubscription.hashCode() : 0);
- result = 31 * result + (nextSubscription != null ? nextSubscription.hashCode() : 0);
- return result;
- }
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java
index bab1259..4fe470a 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java
@@ -33,8 +33,8 @@ public class BusinessSubscriptionTransitionField extends BusinessField {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessSubscriptionTransitionField");
sb.append("{externalKey='").append(externalKey).append('\'');
- sb.append(", name='").append(name).append('\'');
- sb.append(", value='").append(value).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
+ sb.append(", value='").append(getValue()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -53,10 +53,10 @@ public class BusinessSubscriptionTransitionField extends BusinessField {
if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- if (value != null ? !value.equals(that.value) : that.value != null) {
+ if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) {
return false;
}
@@ -66,8 +66,8 @@ public class BusinessSubscriptionTransitionField extends BusinessField {
@Override
public int hashCode() {
int result = externalKey != null ? externalKey.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java
index 522194a..eefa65c 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java
@@ -33,7 +33,7 @@ public class BusinessSubscriptionTransitionTag extends BusinessTag {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessSubscriptionTransitionTag");
sb.append("{externalKey='").append(externalKey).append('\'');
- sb.append(", name='").append(name).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -52,7 +52,7 @@ public class BusinessSubscriptionTransitionTag extends BusinessTag {
if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
@@ -62,7 +62,7 @@ public class BusinessSubscriptionTransitionTag extends BusinessTag {
@Override
public int hashCode() {
int result = externalKey != null ? externalKey.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessTag.java
index 80343e1..64ddaa9 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessTag.java
@@ -17,7 +17,7 @@
package com.ning.billing.analytics.model;
public abstract class BusinessTag {
- protected final String name;
+ private final String name;
public BusinessTag(final String name) {
this.name = name;
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
index c80b6b5..7192e5f 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
+++ b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
@@ -41,6 +41,47 @@ getTransitions(external_key) ::= <<
;
>>
+getTransitionForSubscription(subscription_id) ::= <<
+ select
+ total_ordering
+ , external_key
+ , account_key
+ , requested_timestamp
+ , event
+ , prev_product_name
+ , prev_product_type
+ , prev_product_category
+ , prev_slug
+ , prev_phase
+ , prev_billing_period
+ , prev_price
+ , prev_price_list
+ , prev_mrr
+ , prev_currency
+ , prev_start_date
+ , prev_state
+ , prev_subscription_id
+ , prev_bundle_id
+ , next_product_name
+ , next_product_type
+ , next_product_category
+ , next_slug
+ , next_phase
+ , next_billing_period
+ , next_price
+ , next_price_list
+ , next_mrr
+ , next_currency
+ , next_start_date
+ , next_state
+ , next_subscription_id
+ , next_bundle_id
+ from bst
+ where prev_subscription_id = :subscription_id or next_subscription_id = :subscription_id
+ order by requested_timestamp asc
+ ;
+>>
+
createTransition() ::= <<
insert ignore into bst(
total_ordering
@@ -113,6 +154,50 @@ createTransition() ::= <<
);
>>
+updateTransition() ::= <<
+ update bst set
+ total_ordering = :total_ordering
+ , external_key = :external_key
+ , account_key = :account_key
+ , requested_timestamp = :requested_timestamp
+ , event = :event
+ , prev_product_name = :prev_product_name
+ , prev_product_type = :prev_product_type
+ , prev_product_category = :prev_product_category
+ , prev_slug = :prev_slug
+ , prev_phase = :prev_phase
+ , prev_billing_period = :prev_billing_period
+ , prev_price = :prev_price
+ , prev_price_list = :prev_price_list
+ , prev_mrr = :prev_mrr
+ , prev_currency = :prev_currency
+ , prev_start_date = :prev_start_date
+ , prev_state = :prev_state
+ , prev_subscription_id = :prev_subscription_id
+ , prev_bundle_id = :prev_bundle_id
+ , next_product_name = :next_product_name
+ , next_product_type = :next_product_type
+ , next_product_category = :next_product_category
+ , next_slug = :next_slug
+ , next_phase = :next_phase
+ , next_billing_period = :next_billing_period
+ , next_price = :next_price
+ , next_price_list = :next_price_list
+ , next_mrr = :next_mrr
+ , next_currency = :next_currency
+ , next_start_date = :next_start_date
+ , next_state = :next_state
+ , next_subscription_id = :next_subscription_id
+ , next_bundle_id = :next_bundle_id
+ where total_ordering = :total_ordering
+>>
+
+deleteTransitionsForBundle(external_key) ::= <<
+ delete from bst
+ where external_key=:external_key
+ ;
+>>
+
test() ::= <<
select 1 from bst;
>>
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql b/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
index 43aaad8..366570c 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
+++ b/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
@@ -1,6 +1,7 @@
drop table if exists bst;
create table bst (
- total_ordering bigint default 0
+ record_id int(11) unsigned not null auto_increment
+, total_ordering bigint default 0
, external_key varchar(50) not null comment 'Bundle external key'
, account_key varchar(50) not null comment 'Account external key'
, requested_timestamp bigint not null
@@ -33,7 +34,7 @@ create table bst (
, next_state varchar(32) default null
, next_subscription_id varchar(100) default null
, next_bundle_id varchar(100) default null
-, primary key(total_ordering)
+, primary key(record_id)
) engine=innodb comment 'Business Subscription Transitions, track bundles lifecycle';
create index bst_key_index on bst (external_key, requested_timestamp asc);
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 ad54c53..e82b61c 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
@@ -38,7 +38,6 @@ import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
import com.ning.billing.analytics.AnalyticsTestModule;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
import com.ning.billing.analytics.TestWithEmbeddedDB;
import com.ning.billing.analytics.dao.BusinessAccountSqlDao;
@@ -73,6 +72,7 @@ import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.model.DefaultInvoice;
import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import com.ning.billing.mock.MockAccountBuilder;
+import com.ning.billing.mock.MockPlan;
import com.ning.billing.payment.api.DefaultPaymentInfoEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.payment.api.PaymentStatus;
@@ -180,7 +180,6 @@ public class TestAnalyticsService extends TestWithEmbeddedDB {
final DateTime requestedTransitionTime = clock.getUTCNow();
final PriceList priceList = new MockPriceList().setName("something");
-
transition = new DefaultEffectiveSubscriptionEvent(new SubscriptionTransitionData(
UUID.randomUUID(),
subscriptionId,
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
index 5d6b3a6..a953ed2 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
@@ -36,7 +36,6 @@ import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
import com.ning.billing.analytics.TestWithEmbeddedDB;
import com.ning.billing.analytics.utils.Rounder;
@@ -50,6 +49,7 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
public class TestAnalyticsDao extends TestWithEmbeddedDB {
private static final Long TOTAL_ORDERING = 1L;
@@ -113,45 +113,6 @@ public class TestAnalyticsDao extends TestWithEmbeddedDB {
}
@Test(groups = "slow")
- public void testHandleDuplicatedEvents() {
- final BusinessSubscriptionTransition transitionWithNullPrev = new BusinessSubscriptionTransition(
- transition.getTotalOrdering(),
- transition.getExternalKey(),
- transition.getAccountKey(),
- transition.getRequestedTimestamp(),
- transition.getEvent(),
- null,
- transition.getNextSubscription()
- );
-
- businessSubscriptionTransitionSqlDao.createTransition(transitionWithNullPrev);
- List<BusinessSubscriptionTransition> transitions = businessSubscriptionTransitionSqlDao.getTransitions(EXTERNAL_KEY);
- Assert.assertEquals(transitions.size(), 1);
- Assert.assertEquals(transitions.get(0), transitionWithNullPrev);
- // Try to add the same transition, with the same UUID - we should only store one though
- businessSubscriptionTransitionSqlDao.createTransition(transitionWithNullPrev);
- transitions = businessSubscriptionTransitionSqlDao.getTransitions(EXTERNAL_KEY);
- Assert.assertEquals(transitions.size(), 1);
- Assert.assertEquals(transitions.get(0), transitionWithNullPrev);
-
- // Try now to store a look-alike transition (same fields except UUID) - we should store it this time
- final BusinessSubscriptionTransition secondTransitionWithNullPrev = new BusinessSubscriptionTransition(
- 12L,
- transition.getExternalKey(),
- transition.getAccountKey(),
- transition.getRequestedTimestamp(),
- transition.getEvent(),
- null,
- transition.getNextSubscription()
- );
- businessSubscriptionTransitionSqlDao.createTransition(secondTransitionWithNullPrev);
- transitions = businessSubscriptionTransitionSqlDao.getTransitions(EXTERNAL_KEY);
- Assert.assertEquals(transitions.size(), 2);
- Assert.assertTrue(transitions.contains(transitionWithNullPrev));
- Assert.assertTrue(transitions.contains(secondTransitionWithNullPrev));
- }
-
- @Test(groups = "slow")
public void testTransitionsWithNullPrevSubscription() {
final BusinessSubscriptionTransition transitionWithNullPrev = new BusinessSubscriptionTransition(
transition.getTotalOrdering(),
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java b/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
index a442f2a..b54d7ce 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
@@ -21,8 +21,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.skife.jdbi.v2.Transaction;
import org.skife.jdbi.v2.sqlobject.Bind;
+import org.testng.Assert;
+import com.google.common.collect.ImmutableList;
import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionBinder;
import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionSqlDao;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
@@ -36,6 +39,11 @@ public class MockBusinessSubscriptionTransitionSqlDao implements BusinessSubscri
}
@Override
+ public List<BusinessSubscriptionTransition> getTransitionForSubscription(@Bind("subscription_id") final String subscriptionId) {
+ return ImmutableList.<BusinessSubscriptionTransition>of();
+ }
+
+ @Override
public int createTransition(@BusinessSubscriptionTransitionBinder final BusinessSubscriptionTransition transition) {
if (content.get(transition.getExternalKey()) == null) {
content.put(transition.getExternalKey(), new ArrayList<BusinessSubscriptionTransition>());
@@ -45,6 +53,50 @@ public class MockBusinessSubscriptionTransitionSqlDao implements BusinessSubscri
}
@Override
+ public void updateTransition(@Bind("total_ordering") final long totalOrdering, @BusinessSubscriptionTransitionBinder final BusinessSubscriptionTransition updatedFirstTransition) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void deleteTransitionsForBundle(@Bind("external_key") final String externalKey) {
+ content.put(externalKey, new ArrayList<BusinessSubscriptionTransition>());
+ }
+
+ @Override
public void test() {
}
+
+ @Override
+ public void begin() {
+ }
+
+ @Override
+ public void commit() {
+ }
+
+ @Override
+ public void rollback() {
+ }
+
+ @Override
+ public void checkpoint(final String name) {
+ }
+
+ @Override
+ public void release(final String name) {
+ }
+
+ @Override
+ public void rollback(final String name) {
+ }
+
+ @Override
+ public <ReturnType> ReturnType inTransaction(final Transaction<ReturnType, BusinessSubscriptionTransitionSqlDao> func) {
+ try {
+ return func.inTransaction(this, null);
+ } catch (Exception e) {
+ Assert.fail(e.toString());
+ return null;
+ }
+ }
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscription.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscription.java
index c102d35..7a2cbd7 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscription.java
@@ -27,10 +27,7 @@ import org.testng.annotations.Test;
import com.ning.billing.analytics.AnalyticsTestSuite;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
-import com.ning.billing.analytics.MockSubscription;
-import com.ning.billing.analytics.model.BusinessSubscription;
import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.Duration;
@@ -40,6 +37,8 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
+import com.ning.billing.mock.MockSubscription;
import static com.ning.billing.catalog.api.Currency.USD;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java
index 11c6215..de713a8 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java
@@ -25,10 +25,7 @@ import org.testng.annotations.Test;
import com.ning.billing.analytics.AnalyticsTestSuite;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
-import com.ning.billing.analytics.MockSubscription;
-import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.PhaseType;
@@ -37,6 +34,8 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
+import com.ning.billing.mock.MockSubscription;
public class TestBusinessSubscriptionEvent extends AnalyticsTestSuite {
private Product product;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java
index 4c401a6..1e10acf 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java
@@ -26,12 +26,7 @@ import org.testng.annotations.Test;
import com.ning.billing.analytics.AnalyticsTestSuite;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
-import com.ning.billing.analytics.MockSubscription;
-import com.ning.billing.analytics.model.BusinessSubscription;
-import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
-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.PhaseType;
@@ -40,6 +35,8 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
+import com.ning.billing.mock.MockSubscription;
import static com.ning.billing.catalog.api.Currency.USD;
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 75c3ebc..48cefb4 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java
@@ -24,23 +24,24 @@ import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionSqlDao;
-import com.ning.billing.analytics.model.BusinessSubscription;
-import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
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.SubscriptionTransitionType;
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.util.clock.DefaultClock;
public class TestBusinessSubscriptionTransitionRecorder extends AnalyticsTestSuite {
@Test(groups = "fast")
public void testCreateAddOn() throws Exception {
+ final UUID bundleId = UUID.randomUUID();
final UUID externalKey = UUID.randomUUID();
// Setup the catalog
@@ -49,26 +50,10 @@ public class TestBusinessSubscriptionTransitionRecorder extends AnalyticsTestSui
// Setup the dao
final BusinessSubscriptionTransitionSqlDao sqlDao = new MockBusinessSubscriptionTransitionSqlDao();
- // Add a previous subscription to make sure it doesn't impact the addon
- final BusinessSubscription nextPrevSubscription = new BusinessSubscription(UUID.randomUUID().toString(),
- UUID.randomUUID().toString(),
- UUID.randomUUID().toString(),
- Currency.USD,
- new DateTime(DateTimeZone.UTC),
- Subscription.SubscriptionState.ACTIVE,
- UUID.randomUUID(),
- UUID.randomUUID(),
- catalogService.getFullCatalog());
- sqlDao.createTransition(new BusinessSubscriptionTransition(10L,
- externalKey.toString(),
- UUID.randomUUID().toString(),
- new DateTime(DateTimeZone.UTC),
- BusinessSubscriptionEvent.valueOf("ADD_MISC"),
- null,
- nextPrevSubscription));
// Setup the entitlement API
final SubscriptionBundle bundle = Mockito.mock(SubscriptionBundle.class);
+ Mockito.when(bundle.getId()).thenReturn(bundleId);
Mockito.when(bundle.getKey()).thenReturn(externalKey.toString());
final EntitlementUserApi entitlementApi = Mockito.mock(EntitlementUserApi.class);
Mockito.when(entitlementApi.getBundleFromId(Mockito.<UUID>any())).thenReturn(bundle);
@@ -79,19 +64,25 @@ public class TestBusinessSubscriptionTransitionRecorder extends AnalyticsTestSui
final AccountUserApi accountApi = Mockito.mock(AccountUserApi.class);
Mockito.when(accountApi.getAccountById(bundle.getAccountId())).thenReturn(account);
- final BusinessSubscriptionTransitionRecorder recorder = new BusinessSubscriptionTransitionRecorder(sqlDao, catalogService, entitlementApi, accountApi);
-
// Create an new subscription event
final EffectiveSubscriptionEvent eventEffective = Mockito.mock(EffectiveSubscriptionEvent.class);
Mockito.when(eventEffective.getId()).thenReturn(UUID.randomUUID());
+ Mockito.when(eventEffective.getTransitionType()).thenReturn(SubscriptionTransitionType.CREATE);
+ Mockito.when(eventEffective.getSubscriptionId()).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);
+ final Subscription subscription = Mockito.mock(Subscription.class);
+ Mockito.when(subscription.getAllTransitions()).thenReturn(ImmutableList.<EffectiveSubscriptionEvent>of(eventEffective));
+ Mockito.when(entitlementApi.getSubscriptionsForBundle(Mockito.<UUID>any())).thenReturn(ImmutableList.<Subscription>of(subscription));
+
+ final BusinessSubscriptionTransitionRecorder recorder = new BusinessSubscriptionTransitionRecorder(sqlDao, catalogService, entitlementApi, accountApi, new DefaultClock());
+ recorder.rebuildTransitionsForBundle(bundle.getId());
+
+ Assert.assertEquals(sqlDao.getTransitions(externalKey.toString()).size(), 1);
+ final BusinessSubscriptionTransition transition = sqlDao.getTransitions(externalKey.toString()).get(0);
Assert.assertEquals(transition.getTotalOrdering(), (long) eventEffective.getTotalOrdering());
Assert.assertEquals(transition.getAccountKey(), externalKey.toString());
// Make sure all the prev_ columns are null
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
index 6f18739..79e762f 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
@@ -85,7 +85,7 @@ public class TestBusinessTagRecorder extends TestWithEmbeddedDB {
final CatalogService catalogService = new DefaultCatalogService(Mockito.mock(CatalogConfig.class), Mockito.mock(VersionedCatalogLoader.class));
final AddonUtils addonUtils = new AddonUtils(catalogService);
final DefaultNotificationQueueService notificationQueueService = new DefaultNotificationQueueService(dbi, clock);
- final EntitlementDao entitlementDao = new AuditedEntitlementDao(dbi, clock, addonUtils, notificationQueueService, eventBus);
+ final EntitlementDao entitlementDao = new AuditedEntitlementDao(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService);
final PlanAligner planAligner = new PlanAligner(catalogService);
final DefaultSubscriptionApiService apiService = new DefaultSubscriptionApiService(clock, entitlementDao, catalogService, planAligner);
final DefaultSubscriptionFactory subscriptionFactory = new DefaultSubscriptionFactory(apiService, clock, catalogService);
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 ac17237..e75ea1b 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
@@ -31,7 +31,6 @@ import com.ning.billing.junction.api.Blockable;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.entity.Entity;
-
public interface Subscription extends Entity, Blockable {
public boolean cancel(DateTime requestedDate, boolean eot, CallContext context)
@@ -40,7 +39,7 @@ public interface Subscription extends Entity, Blockable {
public boolean uncancel(CallContext context)
throws EntitlementUserApiException;
- public boolean changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate, CallContext context)
+ public boolean changePlan(String productName, BillingPeriod term, String priceList, DateTime requestedDate, CallContext context)
throws EntitlementUserApiException;
public boolean recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
@@ -76,4 +75,6 @@ public interface Subscription extends Entity, Blockable {
public EffectiveSubscriptionEvent getPreviousTransition();
public List<EffectiveSubscriptionEvent> getBillingTransitions();
+
+ public List<EffectiveSubscriptionEvent> getAllTransitions();
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
index 9dadb9e..0c7eeec 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
@@ -38,11 +38,14 @@ import com.ning.billing.analytics.model.BusinessInvoiceItem;
import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
import com.ning.billing.analytics.utils.Rounder;
+import com.ning.billing.api.TestApiListener;
import com.ning.billing.catalog.api.BillingPeriod;
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.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
@@ -52,8 +55,12 @@ import com.ning.billing.util.api.TagDefinitionApiException;
import com.ning.billing.util.dao.ObjectType;
import com.ning.billing.util.tag.TagDefinition;
+import static org.testng.Assert.assertTrue;
+
@Guice(modules = BeatrixModule.class)
public class TestAnalytics extends TestIntegrationBase {
+ private Plan subscriptionPlan;
+
@BeforeMethod(groups = "slow")
public void setUpAnalyticsHandler() throws Exception {
busService.getBus().register(analyticsListener);
@@ -65,7 +72,46 @@ public class TestAnalytics extends TestIntegrationBase {
}
@Test(groups = "slow")
- public void testAnalyticsEvents() throws Exception {
+ public void testCreateAndCancelSubscription() throws Exception {
+ // Create an account
+ final Account account = verifyAccountCreation();
+
+ // Create a bundle
+ final SubscriptionBundle bundle = verifyFirstBundle(account);
+
+ // Add a subscription
+ Subscription subscription = verifyFirstSubscription(account, bundle);
+
+ // Move after trial
+ clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS);
+ busHandler.pushExpectedEvent(TestApiListener.NextEvent.PHASE);
+ busHandler.pushExpectedEvent(TestApiListener.NextEvent.INVOICE);
+ busHandler.pushExpectedEvent(TestApiListener.NextEvent.PAYMENT);
+ Assert.assertTrue(busHandler.isCompleted(DELAY));
+
+ // Check BST - nothing should have changed
+ verifyBSTWithTrialAndEvergreenPhases(account, bundle, subscription);
+
+ // Cancel end of term - refetch the subscription to have the CTD set
+ // (otherwise, cancellation would be immediate)
+ subscription = entitlementUserApi.getSubscriptionFromId(subscription.getId());
+ subscription.cancel(clock.getUTCNow(), true, context);
+
+ waitALittle();
+
+ verifyBSTWithTrialAndEvergreenPhasesAndCancellation(account, bundle, subscription);
+
+ // Move after cancel date
+ clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS + 100);
+ assertTrue(busHandler.isCompleted(DELAY));
+ waitALittle();
+
+ // Check BST received the system cancel event
+ verifyBSTWithTrialAndEvergreenPhasesAndCancellationAndSystemCancellation(account, bundle, subscription);
+ }
+
+ @Test(groups = "slow")
+ public void testCreateAndUpdateSubscription() throws Exception {
// Create an account
final Account account = verifyAccountCreation();
@@ -192,35 +238,12 @@ public class TestAnalytics extends TestIntegrationBase {
final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
final PlanPhaseSpecifier phaseSpecifier = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null);
final Subscription subscription = entitlementUserApi.createSubscription(bundle.getId(), phaseSpecifier, null, context);
+ subscriptionPlan = subscription.getCurrentPlan();
waitALittle();
- // BST should have one transition
- final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
- Assert.assertEquals(transitions.size(), 1);
- final BusinessSubscriptionTransition transition = transitions.get(0);
- Assert.assertEquals(transition.getExternalKey(), bundle.getKey());
- Assert.assertEquals(transition.getAccountKey(), account.getExternalKey());
- Assert.assertEquals(transition.getEvent().getCategory(), phaseSpecifier.getProductCategory());
- Assert.assertEquals(transition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.ADD);
-
- // This is the first transition
- Assert.assertNull(transition.getPreviousSubscription());
-
- Assert.assertEquals(transition.getNextSubscription().getBillingPeriod(), subscription.getCurrentPhase().getBillingPeriod().toString());
- Assert.assertEquals(transition.getNextSubscription().getBundleId(), subscription.getBundleId());
- Assert.assertEquals(transition.getNextSubscription().getCurrency(), account.getCurrency().toString());
- Assert.assertEquals(transition.getNextSubscription().getPhase(), subscription.getCurrentPhase().getPhaseType().toString());
- // Trial: fixed price of zero
- Assert.assertEquals(transition.getNextSubscription().getPrice().doubleValue(), subscription.getCurrentPhase().getFixedPrice().getPrice(account.getCurrency()).doubleValue());
- Assert.assertEquals(transition.getNextSubscription().getPriceList(), subscription.getCurrentPriceList().getName());
- Assert.assertEquals(transition.getNextSubscription().getProductCategory(), subscription.getCurrentPlan().getProduct().getCategory());
- Assert.assertEquals(transition.getNextSubscription().getProductName(), subscription.getCurrentPlan().getProduct().getName());
- Assert.assertEquals(transition.getNextSubscription().getProductType(), subscription.getCurrentPlan().getProduct().getCatalogName());
- Assert.assertEquals(transition.getNextSubscription().getSlug(), subscription.getCurrentPhase().getName());
- Assert.assertEquals(transition.getNextSubscription().getStartDate(), subscription.getStartDate());
- Assert.assertEquals(transition.getNextSubscription().getState(), subscription.getState());
- Assert.assertEquals(transition.getNextSubscription().getSubscriptionId(), subscription.getId());
+ // Verify BST
+ verifyBSTWithTrialAndEvergreenPhases(account, bundle, subscription);
// Make sure the account balance is still zero
final BusinessAccount businessAccount = analyticsUserApi.getAccountByKey(account.getExternalKey());
@@ -260,6 +283,118 @@ public class TestAnalytics extends TestIntegrationBase {
return subscription;
}
+ private void verifyBSTWithTrialAndEvergreenPhases(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws CatalogApiException {
+ // BST should have two transitions
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+ Assert.assertEquals(transitions.size(), 2);
+
+ verifyTrialAndEvergreenPhases(account, bundle, subscription);
+ }
+
+ private void verifyBSTWithTrialAndEvergreenPhasesAndCancellation(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws CatalogApiException {
+ // BST should have three transitions
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+ Assert.assertEquals(transitions.size(), 3);
+
+ verifyTrialAndEvergreenPhases(account, bundle, subscription);
+ verifyCancellationTransition(account, bundle);
+ }
+
+ private void verifyBSTWithTrialAndEvergreenPhasesAndCancellationAndSystemCancellation(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws CatalogApiException {
+ // BST should have four transitions
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+ Assert.assertEquals(transitions.size(), 4);
+
+ verifyTrialAndEvergreenPhases(account, bundle, subscription);
+ verifyCancellationTransition(account, bundle);
+ verifySystemCancellationTransition(account, bundle);
+ }
+
+ private void verifyTrialAndEvergreenPhases(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws CatalogApiException {
+ final Product currentProduct = subscriptionPlan.getProduct();
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+
+ // Check the first transition (into trial phase)
+ final BusinessSubscriptionTransition initialTransition = transitions.get(0);
+ Assert.assertEquals(initialTransition.getExternalKey(), bundle.getKey());
+ Assert.assertEquals(initialTransition.getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(initialTransition.getEvent().getCategory(), currentProduct.getCategory());
+ Assert.assertEquals(initialTransition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.ADD);
+
+ // This is the first transition
+ Assert.assertNull(initialTransition.getPreviousSubscription());
+
+ Assert.assertEquals(initialTransition.getNextSubscription().getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD.toString());
+ Assert.assertEquals(initialTransition.getNextSubscription().getBundleId(), subscription.getBundleId());
+ Assert.assertEquals(initialTransition.getNextSubscription().getCurrency(), account.getCurrency().toString());
+ Assert.assertEquals(initialTransition.getNextSubscription().getPhase(), PhaseType.TRIAL.toString());
+ // Trial: fixed price of zero
+ Assert.assertEquals(initialTransition.getNextSubscription().getPrice().doubleValue(), (double) 0);
+ Assert.assertEquals(initialTransition.getNextSubscription().getPriceList(), subscription.getCurrentPriceList().getName());
+ Assert.assertEquals(initialTransition.getNextSubscription().getProductCategory(), currentProduct.getCategory());
+ Assert.assertEquals(initialTransition.getNextSubscription().getProductName(), currentProduct.getName());
+ Assert.assertEquals(initialTransition.getNextSubscription().getProductType(), currentProduct.getCatalogName());
+ Assert.assertEquals(initialTransition.getNextSubscription().getSlug(), currentProduct.getName().toLowerCase() + "-monthly-trial");
+ Assert.assertEquals(initialTransition.getNextSubscription().getStartDate(), subscription.getStartDate());
+ Assert.assertEquals(initialTransition.getNextSubscription().getState(), Subscription.SubscriptionState.ACTIVE);
+ Assert.assertEquals(initialTransition.getNextSubscription().getSubscriptionId(), subscription.getId());
+
+ // Check the second transition (from trial to evergreen)
+ final BusinessSubscriptionTransition futureTransition = transitions.get(1);
+ Assert.assertEquals(futureTransition.getExternalKey(), bundle.getKey());
+ Assert.assertEquals(futureTransition.getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(futureTransition.getEvent().getCategory(), currentProduct.getCategory());
+ Assert.assertEquals(futureTransition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.SYSTEM_CHANGE);
+
+ Assert.assertEquals(futureTransition.getPreviousSubscription(), initialTransition.getNextSubscription());
+
+ // The billing period should have changed (NO_BILLING_PERIOD for the trial period)
+ Assert.assertEquals(futureTransition.getNextSubscription().getBillingPeriod(), BillingPeriod.MONTHLY.toString());
+ Assert.assertEquals(futureTransition.getNextSubscription().getBundleId(), subscription.getBundleId());
+ Assert.assertEquals(initialTransition.getNextSubscription().getCurrency(), account.getCurrency().toString());
+ // From trial to evergreen
+ Assert.assertEquals(futureTransition.getNextSubscription().getPhase(), PhaseType.EVERGREEN.toString());
+ Assert.assertTrue(futureTransition.getNextSubscription().getPrice().doubleValue() > 0);
+ Assert.assertEquals(futureTransition.getNextSubscription().getPriceList(), subscription.getCurrentPriceList().getName());
+ Assert.assertEquals(futureTransition.getNextSubscription().getProductCategory(), currentProduct.getCategory());
+ Assert.assertEquals(futureTransition.getNextSubscription().getProductName(), currentProduct.getName());
+ Assert.assertEquals(futureTransition.getNextSubscription().getProductType(), currentProduct.getCatalogName());
+ Assert.assertEquals(futureTransition.getNextSubscription().getSlug(), currentProduct.getName().toLowerCase() + "-monthly-evergreen");
+ // 30 days trial
+ Assert.assertEquals(futureTransition.getNextSubscription().getStartDate(), subscription.getStartDate().plusDays(30));
+ Assert.assertEquals(futureTransition.getNextSubscription().getState(), Subscription.SubscriptionState.ACTIVE);
+ Assert.assertEquals(futureTransition.getNextSubscription().getSubscriptionId(), subscription.getId());
+ }
+
+ private void verifyCancellationTransition(final Account account, final SubscriptionBundle bundle) throws CatalogApiException {
+ final Product currentProduct = subscriptionPlan.getProduct();
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+
+ final BusinessSubscriptionTransition cancellationRequest = transitions.get(2);
+ Assert.assertEquals(cancellationRequest.getExternalKey(), bundle.getKey());
+ Assert.assertEquals(cancellationRequest.getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(cancellationRequest.getEvent().getCategory(), currentProduct.getCategory());
+ Assert.assertEquals(cancellationRequest.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.CANCEL);
+
+ Assert.assertNull(cancellationRequest.getNextSubscription());
+ // The actual content has already been checked in verifyTrialAndEvergreenPhases
+ Assert.assertEquals(cancellationRequest.getPreviousSubscription(), transitions.get(1).getNextSubscription());
+ }
+
+ private void verifySystemCancellationTransition(final Account account, final SubscriptionBundle bundle) throws CatalogApiException {
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+
+ final BusinessSubscriptionTransition systemCancellation = transitions.get(3);
+ Assert.assertEquals(systemCancellation.getExternalKey(), bundle.getKey());
+ Assert.assertEquals(systemCancellation.getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(systemCancellation.getEvent().getCategory(), ProductCategory.BASE);
+ Assert.assertEquals(systemCancellation.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.SYSTEM_CANCEL);
+
+ Assert.assertNull(systemCancellation.getNextSubscription());
+ // The actual content has already been checked in verifyTrialAndEvergreenPhases
+ Assert.assertEquals(systemCancellation.getPreviousSubscription(), transitions.get(1).getNextSubscription());
+ }
+
private void verifyChangePlan(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws EntitlementUserApiException, InterruptedException {
final String newProductName = "Assault-Rifle";
final BillingPeriod newTerm = BillingPeriod.MONTHLY;
@@ -269,9 +404,9 @@ public class TestAnalytics extends TestIntegrationBase {
waitALittle();
- // BST should have two transitions
+ // BST should have three transitions (a ADD_BASE, CHANGE_BASE and SYSTEM_CHANGE_BASE)
final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
- Assert.assertEquals(transitions.size(), 2);
+ Assert.assertEquals(transitions.size(), 3);
final BusinessSubscriptionTransition previousTransition = transitions.get(0);
final BusinessSubscriptionTransition transition = transitions.get(1);
Assert.assertEquals(transition.getExternalKey(), bundle.getKey());
@@ -317,6 +452,6 @@ public class TestAnalytics extends TestIntegrationBase {
private void waitALittle() throws InterruptedException {
// We especially need to wait for entitlement events
- Thread.sleep(2000);
+ Thread.sleep(4000);
}
}
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 368dbb5..220c2ad 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
@@ -37,6 +37,7 @@ import com.ning.billing.entitlement.api.SubscriptionFactory;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
@@ -323,7 +324,7 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
if (nbDeleted != deletedEvents.size()) {
for (final SubscriptionTimeline.DeletedEvent d : deletedEvents) {
boolean found = false;
- for (final SubscriptionTransitionData cur : data.getAllTransitions()) {
+ for (final EffectiveSubscriptionEvent cur : data.getAllTransitions()) {
if (cur.getId().equals(d.getEventId())) {
found = true;
}
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 cdc6797..66cf27c 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
@@ -165,7 +165,7 @@ public class SubscriptionDataRepair extends SubscriptionData {
.setRequestedDate(now)
.setUserToken(context.getUserToken())
.setFromDisk(true));
- repairDao.cancelSubscription(cur.getId(), cancelEvent, context, 0);
+ repairDao.cancelSubscription(cur, cancelEvent, context, 0);
cur.rebuildTransitions(repairDao.getEventsForSubscription(cur.getId()), catalogService.getFullCatalog());
}
}
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
index f03ba35..38b6b98 100644
--- 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
@@ -23,6 +23,7 @@ import org.joda.time.DateTime;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
+import com.ning.billing.entitlement.events.EntitlementEvent;
public class DefaultRequestedSubscriptionEvent extends DefaultSubscriptionEvent implements RequestedSubscriptionEvent {
public DefaultRequestedSubscriptionEvent(final SubscriptionTransitionData in, final DateTime startDate) {
@@ -52,4 +53,9 @@ public class DefaultRequestedSubscriptionEvent extends DefaultSubscriptionEvent
previousPhase, previousPriceList, nextState, nextPlan, nextPhase, nextPriceList, totalOrdering, userToken,
transitionType, remainingEventsForUserOperation, startDate);
}
+
+ public DefaultRequestedSubscriptionEvent(final SubscriptionData subscription, final EntitlementEvent nextEvent) {
+ this(nextEvent.getId(), nextEvent.getSubscriptionId(), subscription.getBundleId(), nextEvent.getRequestedDate(), nextEvent.getEffectiveDate(),
+ null, null, null, null, null, null, null, null, nextEvent.getTotalOrdering(), null, null, 0, null);
+ }
}
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 4469661..99e3e58 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
@@ -139,7 +139,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
events.add(nextPhaseEvent);
}
if (reCreate) {
- dao.recreateSubscription(subscription.getId(), events, context);
+ dao.recreateSubscription(subscription, events, context);
} else {
dao.createSubscription(subscription, events, context);
}
@@ -179,7 +179,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
.setUserToken(context.getUserToken())
.setFromDisk(true));
- dao.cancelSubscription(subscription.getId(), cancelEvent, context, 0);
+ dao.cancelSubscription(subscription, cancelEvent, context, 0);
subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
return (policy == ActionPolicy.IMMEDIATE);
} catch (CatalogApiException e) {
@@ -213,7 +213,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
uncancelEvents.add(nextPhaseEvent);
}
- dao.uncancelSubscription(subscription.getId(), uncancelEvents, context);
+ dao.uncancelSubscription(subscription, uncancelEvents, context);
subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
return true;
@@ -285,7 +285,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
changeEvents.add(nextPhaseEvent);
}
changeEvents.add(changeEvent);
- dao.changePlan(subscription.getId(), changeEvents, context);
+ dao.changePlan(subscription, changeEvents, context);
subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
return (policy == ActionPolicy.IMMEDIATE);
} catch (CatalogApiException e) {
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 409bc8d..d5586e9 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
@@ -303,8 +303,19 @@ public class SubscriptionData extends EntityBase implements Subscription {
return activeVersion;
}
- public List<SubscriptionTransitionData> getAllTransitions() {
- return transitions;
+ @Override
+ public List<EffectiveSubscriptionEvent> getAllTransitions() {
+ if (transitions == null) {
+ return Collections.emptyList();
+ }
+
+ final List<EffectiveSubscriptionEvent> result = new ArrayList<EffectiveSubscriptionEvent>();
+ final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions, Order.ASC_FROM_PAST, Kind.ALL, Visibility.ALL, TimeLimit.ALL);
+ while (it.hasNext()) {
+ result.add(new DefaultEffectiveSubscriptionEvent(it.next(), startDate));
+ }
+
+ return result;
}
public SubscriptionTransitionData getInitialTransitionForCurrentPlan() {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
index ac54ea3..d3707fa 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
@@ -30,8 +30,6 @@ import com.ning.billing.entitlement.events.user.ApiEventType;
import com.ning.billing.entitlement.exceptions.EntitlementError;
public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
-
-
private final Long totalOrdering;
private final UUID subscriptionId;
private final UUID bundleId;
@@ -52,7 +50,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
private final Integer remainingEventsForUserOperation;
private final UUID userToken;
-
public SubscriptionTransitionData(final UUID eventId,
final UUID subscriptionId,
final UUID bundleId,
@@ -71,7 +68,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
final Long totalOrdering,
final UUID userToken,
final Boolean isFromDisk) {
- super();
this.eventId = eventId;
this.subscriptionId = subscriptionId;
this.bundleId = bundleId;
@@ -116,7 +112,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
this.remainingEventsForUserOperation = remainingEventsForUserOperation;
}
-
public UUID getId() {
return eventId;
}
@@ -153,7 +148,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
return nextState;
}
-
public PriceList getPreviousPriceList() {
return previousPriceList;
}
@@ -170,7 +164,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
return remainingEventsForUserOperation;
}
-
public SubscriptionTransitionType getTransitionType() {
return toSubscriptionTransitionType(eventType, apiEventType);
}
@@ -194,7 +187,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
return effectiveTransitionTime;
}
-
public Long getTotalOrdering() {
return totalOrdering;
}
@@ -211,21 +203,126 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
return eventType;
}
-
@Override
public String toString() {
- return "SubscriptionTransition [eventId=" + eventId
- + ", subscriptionId=" + subscriptionId
- + ", eventType=" + eventType + ", apiEventType="
- + apiEventType + ", requestedTransitionTime=" + requestedTransitionTime
- + ", effectiveTransitionTime=" + effectiveTransitionTime
- + ", previousState=" + previousState + ", previousPlan="
- + ((previousPlan != null) ? previousPlan.getName() : null)
- + ", previousPhase=" + ((previousPhase != null) ? previousPhase.getName() : null)
- + ", previousPriceList " + previousPriceList
- + ", nextState=" + nextState
- + ", nextPlan=" + ((nextPlan != null) ? nextPlan.getName() : null)
- + ", nextPriceList " + nextPriceList
- + ", nextPhase=" + ((nextPhase != null) ? nextPhase.getName() : null) + "]";
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SubscriptionTransitionData");
+ sb.append("{apiEventType=").append(apiEventType);
+ sb.append(", totalOrdering=").append(totalOrdering);
+ sb.append(", subscriptionId=").append(subscriptionId);
+ sb.append(", bundleId=").append(bundleId);
+ sb.append(", eventId=").append(eventId);
+ sb.append(", eventType=").append(eventType);
+ sb.append(", requestedTransitionTime=").append(requestedTransitionTime);
+ sb.append(", effectiveTransitionTime=").append(effectiveTransitionTime);
+ sb.append(", previousState=").append(previousState);
+ sb.append(", previousPriceList=").append(previousPriceList);
+ sb.append(", previousPlan=").append(previousPlan);
+ sb.append(", previousPhase=").append(previousPhase);
+ sb.append(", nextState=").append(nextState);
+ sb.append(", nextPriceList=").append(nextPriceList);
+ sb.append(", nextPlan=").append(nextPlan);
+ sb.append(", nextPhase=").append(nextPhase);
+ sb.append(", isFromDisk=").append(isFromDisk);
+ sb.append(", remainingEventsForUserOperation=").append(remainingEventsForUserOperation);
+ sb.append(", userToken=").append(userToken);
+ 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 SubscriptionTransitionData that = (SubscriptionTransitionData) o;
+
+ if (apiEventType != that.apiEventType) {
+ return false;
+ }
+ if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
+ return false;
+ }
+ if (effectiveTransitionTime != null ? effectiveTransitionTime.compareTo(that.effectiveTransitionTime) != 0 : that.effectiveTransitionTime != null) {
+ return false;
+ }
+ if (eventId != null ? !eventId.equals(that.eventId) : that.eventId != null) {
+ return false;
+ }
+ if (eventType != that.eventType) {
+ return false;
+ }
+ if (isFromDisk != null ? !isFromDisk.equals(that.isFromDisk) : that.isFromDisk != null) {
+ return false;
+ }
+ if (nextPhase != null ? !nextPhase.equals(that.nextPhase) : that.nextPhase != null) {
+ return false;
+ }
+ if (nextPlan != null ? !nextPlan.equals(that.nextPlan) : that.nextPlan != null) {
+ return false;
+ }
+ if (nextPriceList != null ? !nextPriceList.equals(that.nextPriceList) : that.nextPriceList != null) {
+ return false;
+ }
+ if (nextState != that.nextState) {
+ return false;
+ }
+ if (previousPhase != null ? !previousPhase.equals(that.previousPhase) : that.previousPhase != null) {
+ return false;
+ }
+ if (previousPlan != null ? !previousPlan.equals(that.previousPlan) : that.previousPlan != null) {
+ return false;
+ }
+ if (previousPriceList != null ? !previousPriceList.equals(that.previousPriceList) : that.previousPriceList != null) {
+ return false;
+ }
+ if (previousState != that.previousState) {
+ return false;
+ }
+ if (remainingEventsForUserOperation != null ? !remainingEventsForUserOperation.equals(that.remainingEventsForUserOperation) : that.remainingEventsForUserOperation != null) {
+ return false;
+ }
+ if (requestedTransitionTime != null ? requestedTransitionTime.compareTo(that.requestedTransitionTime) != 0 : that.requestedTransitionTime != null) {
+ return false;
+ }
+ if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
+ return false;
+ }
+ if (totalOrdering != null ? !totalOrdering.equals(that.totalOrdering) : that.totalOrdering != null) {
+ return false;
+ }
+ if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ 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 + (eventType != null ? eventType.hashCode() : 0);
+ result = 31 * result + (apiEventType != null ? apiEventType.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 + (isFromDisk != null ? isFromDisk.hashCode() : 0);
+ result = 31 * result + (remainingEventsForUserOperation != null ? remainingEventsForUserOperation.hashCode() : 0);
+ result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
+ return result;
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index a4a926e..57b21d3 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -16,15 +16,11 @@
package com.ning.billing.entitlement.engine.core;
-
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;
-
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,8 +65,6 @@ import com.ning.billing.util.notificationq.NotificationQueueService.Notification
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
public class Engine implements EventListener, EntitlementService {
-
-
public static final String NOTIFICATION_QUEUE_NAME = "subscription-events";
public static final String ENTITLEMENT_SERVICE_NAME = "entitlement-service";
@@ -81,21 +75,20 @@ public class Engine implements EventListener, EntitlementService {
private final PlanAligner planAligner;
private final AddonUtils addonUtils;
private final Bus eventBus;
-
private final EntitlementConfig config;
private final NotificationQueueService notificationQueueService;
private final CallContextFactory factory;
private final SubscriptionFactory subscriptionFactory;
+
private NotificationQueue subscriptionEventQueue;
@Inject
public Engine(final Clock clock, final EntitlementDao dao, final PlanAligner planAligner,
- final EntitlementConfig config,
- final AddonUtils addonUtils, final Bus eventBus,
- final NotificationQueueService notificationQueueService,
- final SubscriptionFactory subscriptionFactory,
- final CallContextFactory factory) {
- super();
+ final EntitlementConfig config,
+ final AddonUtils addonUtils, final Bus eventBus,
+ final NotificationQueueService notificationQueueService,
+ final SubscriptionFactory subscriptionFactory,
+ final CallContextFactory factory) {
this.clock = clock;
this.dao = dao;
this.planAligner = planAligner;
@@ -114,32 +107,29 @@ public class Engine implements EventListener, EntitlementService {
@LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
public void initialize() {
-
try {
- subscriptionEventQueue = notificationQueueService.createNotificationQueue(ENTITLEMENT_SERVICE_NAME,
- NOTIFICATION_QUEUE_NAME,
- new NotificationQueueHandler() {
+ final NotificationQueueHandler queueHandler = new NotificationQueueHandler() {
@Override
public void handleReadyNotification(final NotificationKey inputKey, final DateTime eventDateTime) {
-
- if (! (inputKey instanceof EntitlementNotificationKey)) {
+ if (!(inputKey instanceof EntitlementNotificationKey)) {
log.error("Entitlement service received an unexpected event type {}" + inputKey.getClass().getName());
return;
}
- EntitlementNotificationKey key = (EntitlementNotificationKey) inputKey;
-
- final EntitlementEvent event = dao.getEventById(key.getEventId());
+
+ final EntitlementNotificationKey key = (EntitlementNotificationKey) inputKey;
+ final EntitlementEvent event = dao.getEventById(key.getEventId());
if (event == null) {
log.warn("Failed to extract event for notification key {}", inputKey);
return;
}
+
final UUID userToken = (event.getType() == EventType.API_USER) ? ((ApiEvent) event).getUserToken() : null;
final CallContext context = factory.createCallContext("SubscriptionEventQueue", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
processEventReady(event, key.getSeqId(), context);
}
- },
- new NotificationConfig() {
+ };
+ final NotificationConfig notificationConfig = new NotificationConfig() {
@Override
public long getSleepTimeMs() {
return config.getSleepTimeMs();
@@ -149,8 +139,12 @@ public class Engine implements EventListener, EntitlementService {
public boolean isNotificationProcessingOff() {
return config.isNotificationProcessingOff();
}
- }
- );
+ };
+
+ subscriptionEventQueue = notificationQueueService.createNotificationQueue(ENTITLEMENT_SERVICE_NAME,
+ NOTIFICATION_QUEUE_NAME,
+ queueHandler,
+ notificationConfig);
} catch (NotificationQueueAlreadyExists e) {
throw new RuntimeException(e);
}
@@ -169,12 +163,12 @@ public class Engine implements EventListener, EntitlementService {
}
}
-
@Override
public void processEventReady(final EntitlementEvent event, final int seqId, final CallContext context) {
if (!event.isActive()) {
return;
}
+
final SubscriptionData subscription = (SubscriptionData) dao.getSubscriptionFromId(subscriptionFactory, event.getSubscriptionId());
if (subscription == null) {
log.warn("Failed to retrieve subscription for id %s", event.getSubscriptionId());
@@ -192,10 +186,10 @@ public class Engine implements EventListener, EntitlementService {
int theRealSeqId = seqId;
if (event.getType() == EventType.PHASE) {
onPhaseEvent(subscription, context);
- } else if (event.getType() == EventType.API_USER &&
- subscription.getCategory() == ProductCategory.BASE) {
+ } else if (event.getType() == EventType.API_USER && subscription.getCategory() == ProductCategory.BASE) {
theRealSeqId = onBasePlanEvent(subscription, (ApiEvent) event, context);
}
+
try {
eventBus.post(subscription.getTransitionFromEvent(event, theRealSeqId));
} catch (EventBusException e) {
@@ -203,41 +197,36 @@ public class Engine implements EventListener, EntitlementService {
}
}
-
private void onPhaseEvent(final SubscriptionData subscription, final CallContext context) {
try {
final DateTime now = clock.getUTCNow();
final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now);
final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, now, nextTimedPhase.getStartPhase()) :
- null;
- if (nextPhaseEvent != null) {
- dao.createNextPhaseEvent(subscription.getId(), nextPhaseEvent, context);
- }
+ null;
+ if (nextPhaseEvent != null) {
+ dao.createNextPhaseEvent(subscription, nextPhaseEvent, context);
+ }
} catch (EntitlementError e) {
log.error(String.format("Failed to insert next phase for subscription %s", subscription.getId()), e);
}
}
private int onBasePlanEvent(final SubscriptionData baseSubscription, final ApiEvent event, final CallContext context) {
-
final DateTime now = clock.getUTCNow();
-
- final Product baseProduct = (baseSubscription.getState() == SubscriptionState.CANCELLED) ?
- null : baseSubscription.getCurrentPlan().getProduct();
+ final Product baseProduct = (baseSubscription.getState() == SubscriptionState.CANCELLED) ? null : baseSubscription.getCurrentPlan().getProduct();
final List<Subscription> subscriptions = dao.getSubscriptions(subscriptionFactory, baseSubscription.getBundleId());
-
final Map<UUID, EntitlementEvent> addOnCancellations = new HashMap<UUID, EntitlementEvent>();
-
- final Iterator<Subscription> it = subscriptions.iterator();
- while (it.hasNext()) {
- final SubscriptionData cur = (SubscriptionData) it.next();
+ final Map<UUID, SubscriptionData> addOnCancellationSubscriptions = new HashMap<UUID, SubscriptionData>();
+ for (final Subscription subscription : subscriptions) {
+ final SubscriptionData cur = (SubscriptionData) subscription;
if (cur.getState() == SubscriptionState.CANCELLED ||
cur.getCategory() != ProductCategory.ADD_ON) {
continue;
}
+
final Plan addonCurrentPlan = cur.getCurrentPlan();
if (baseProduct == null ||
addonUtils.isAddonIncluded(baseProduct, addonCurrentPlan) ||
@@ -246,23 +235,26 @@ public class Engine implements EventListener, EntitlementService {
// Perform AO cancellation using the effectiveDate of the BP
//
final EntitlementEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
- .setSubscriptionId(cur.getId())
- .setActiveVersion(cur.getActiveVersion())
- .setProcessedDate(now)
- .setEffectiveDate(event.getEffectiveDate())
- .setRequestedDate(now)
- .setUserToken(context.getUserToken())
- .setFromDisk(true));
+ .setSubscriptionId(cur.getId())
+ .setActiveVersion(cur.getActiveVersion())
+ .setProcessedDate(now)
+ .setEffectiveDate(event.getEffectiveDate())
+ .setRequestedDate(now)
+ .setUserToken(context.getUserToken())
+ .setFromDisk(true));
addOnCancellations.put(cur.getId(), cancelEvent);
+ addOnCancellationSubscriptions.put(cur.getId(), cur);
}
}
+
final int addOnSize = addOnCancellations.size();
int cancelSeq = addOnSize - 1;
for (final UUID key : addOnCancellations.keySet()) {
- dao.cancelSubscription(key, addOnCancellations.get(key), context, cancelSeq);
+ dao.cancelSubscription(addOnCancellationSubscriptions.get(key), addOnCancellations.get(key), context, cancelSeq);
cancelSeq--;
}
+
return addOnSize;
}
}
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 2d7f212..24c7cca 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
@@ -40,6 +40,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.inject.Inject;
import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionFactory;
@@ -49,6 +50,7 @@ import com.ning.billing.entitlement.api.migration.AccountMigrationData.Subscript
import com.ning.billing.entitlement.api.timeline.DefaultRepairEntitlementEvent;
import com.ning.billing.entitlement.api.timeline.RepairEntitlementEvent;
import com.ning.billing.entitlement.api.timeline.SubscriptionDataRepair;
+import com.ning.billing.entitlement.api.user.DefaultRequestedSubscriptionEvent;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
@@ -87,10 +89,11 @@ public class AuditedEntitlementDao implements EntitlementDao {
private final NotificationQueueService notificationQueueService;
private final AddonUtils addonUtils;
private final Bus eventBus;
+ private final CatalogService catalogService;
@Inject
public AuditedEntitlementDao(final IDBI dbi, final Clock clock, final AddonUtils addonUtils,
- final NotificationQueueService notificationQueueService, final Bus eventBus) {
+ final NotificationQueueService notificationQueueService, final Bus eventBus, final CatalogService catalogService) {
this.clock = clock;
this.subscriptionsDao = dbi.onDemand(SubscriptionSqlDao.class);
this.eventsDao = dbi.onDemand(EntitlementEventSqlDao.class);
@@ -98,6 +101,7 @@ public class AuditedEntitlementDao implements EntitlementDao {
this.notificationQueueService = notificationQueueService;
this.addonUtils = addonUtils;
this.eventBus = eventBus;
+ this.catalogService = catalogService;
}
@Override
@@ -206,10 +210,11 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
@Override
- public void createNextPhaseEvent(final UUID subscriptionId, final EntitlementEvent nextPhase, final CallContext context) {
+ public void createNextPhaseEvent(final SubscriptionData subscription, final EntitlementEvent nextPhase, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
+ final UUID subscriptionId = subscription.getId();
cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
transactional.insertEvent(nextPhase, context);
@@ -221,6 +226,9 @@ public class AuditedEntitlementDao implements EntitlementDao {
nextPhase.getEffectiveDate(),
new EntitlementNotificationKey(nextPhase.getId()));
+ // Notify the Bus of the requested change
+ notifyBusOfRequestedChange(transactional, subscription, nextPhase);
+
return null;
}
});
@@ -290,13 +298,19 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
eventsDaoFromSameTransaction.insertAuditFromTransaction(audits, context);
+
+ // Notify the Bus of the latest requested change, if needed
+ if (initialEvents.size() > 0) {
+ notifyBusOfRequestedChange(eventsDaoFromSameTransaction, subscription, initialEvents.get(initialEvents.size() - 1));
+ }
+
return null;
}
});
}
@Override
- public void recreateSubscription(final UUID subscriptionId, final List<EntitlementEvent> recreateEvents, final CallContext context) {
+ public void recreateSubscription(final SubscriptionData subscription, final List<EntitlementEvent> recreateEvents, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
public Void inTransaction(final EntitlementEventSqlDao transactional,
@@ -313,16 +327,21 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
transactional.insertAuditFromTransaction(audits, context);
+
+ // Notify the Bus of the latest requested change
+ notifyBusOfRequestedChange(transactional, subscription, recreateEvents.get(recreateEvents.size() - 1));
+
return null;
}
});
}
@Override
- public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context, final int seqId) {
+ public void cancelSubscription(final SubscriptionData subscription, 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 {
+ final UUID subscriptionId = subscription.getId();
cancelNextCancelEventFromTransaction(subscriptionId, transactional, context);
cancelNextChangeEventFromTransaction(subscriptionId, transactional, context);
cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
@@ -336,16 +355,21 @@ public class AuditedEntitlementDao implements EntitlementDao {
recordFutureNotificationFromTransaction(transactional,
cancelEvent.getEffectiveDate(),
new EntitlementNotificationKey(cancelEvent.getId(), seqId));
+
+ // Notify the Bus of the requested change
+ notifyBusOfRequestedChange(transactional, subscription, cancelEvent);
+
return null;
}
});
}
@Override
- public void uncancelSubscription(final UUID subscriptionId, final List<EntitlementEvent> uncancelEvents, final CallContext context) {
+ public void uncancelSubscription(final SubscriptionData subscription, 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 {
+ final UUID subscriptionId = subscription.getId();
EntitlementEvent cancelledEvent = null;
final Date now = clock.getUTCNow().toDate();
final List<EntitlementEvent> events = transactional.getFutureActiveEventForSubscription(subscriptionId.toString(), now);
@@ -377,17 +401,22 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
transactional.insertAuditFromTransaction(eventAudits, context);
+
+ // Notify the Bus of the latest requested change
+ notifyBusOfRequestedChange(transactional, subscription, uncancelEvents.get(uncancelEvents.size() - 1));
}
+
return null;
}
});
}
@Override
- public void changePlan(final UUID subscriptionId, final List<EntitlementEvent> changeEvents, final CallContext context) {
+ public void changePlan(final SubscriptionData subscription, final List<EntitlementEvent> changeEvents, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
+ final UUID subscriptionId = subscription.getId();
cancelNextChangeEventFromTransaction(subscriptionId, transactional, context);
cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
@@ -403,6 +432,11 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
transactional.insertAuditFromTransaction(eventAudits, context);
+
+ // Notify the Bus of the latest requested change
+ final EntitlementEvent finalEvent = changeEvents.get(changeEvents.size() - 1);
+ notifyBusOfRequestedChange(transactional, subscription, finalEvent);
+
return null;
}
});
@@ -559,7 +593,6 @@ public class AuditedEntitlementDao implements EntitlementDao {
final SubscriptionBundleData bundleData = curBundle.getData();
for (final SubscriptionMigrationData curSubscription : curBundle.getSubscriptions()) {
-
final SubscriptionData subData = curSubscription.getData();
for (final EntitlementEvent curEvent : curSubscription.getInitialEvents()) {
transactional.insertEvent(curEvent, context);
@@ -573,7 +606,12 @@ public class AuditedEntitlementDao implements EntitlementDao {
transSubDao.insertSubscription(subData, context);
recordId = transSubDao.getRecordId(subData.getId().toString());
audits.add(new EntityAudit(TableName.SUBSCRIPTIONS, recordId, ChangeType.INSERT));
+
+ // Notify the Bus of the latest requested change
+ final EntitlementEvent finalEvent = curSubscription.getInitialEvents().get(curSubscription.getInitialEvents().size() - 1);
+ notifyBusOfRequestedChange(transactional, subData, finalEvent);
}
+
transBundleDao.insertBundle(bundleData, context);
recordId = transBundleDao.getRecordId(bundleData.getId().toString());
audits.add(new EntityAudit(TableName.BUNDLES, recordId, ChangeType.INSERT));
@@ -608,6 +646,7 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
try {
+ // Note: we don't send a requested change event here, but a repair event
final RepairEntitlementEvent busEvent = new DefaultRepairEntitlementEvent(context.getUserToken(), accountId, bundleId, clock.getUTCNow());
eventBus.postFromTransaction(busEvent, transactional);
} catch (EventBusException e) {
@@ -641,4 +680,12 @@ public class AuditedEntitlementDao implements EntitlementDao {
throw new RuntimeException(e);
}
}
+
+ private void notifyBusOfRequestedChange(final EntitlementEventSqlDao transactional, final SubscriptionData subscription, final EntitlementEvent nextEvent) {
+ try {
+ eventBus.postFromTransaction(new DefaultRequestedSubscriptionEvent(subscription, nextEvent), transactional);
+ } catch (EventBusException e) {
+ log.warn("Failed to post requested change event for subscription " + subscription.getId(), e);
+ }
+ }
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
index 710391b..b85a47a 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
@@ -56,7 +56,7 @@ public interface EntitlementDao {
public void updateChargedThroughDate(final SubscriptionData subscription, final CallContext context);
// Event apis
- public void createNextPhaseEvent(final UUID subscriptionId, final EntitlementEvent nextPhase, final CallContext context);
+ public void createNextPhaseEvent(final SubscriptionData subscription, final EntitlementEvent nextPhase, final CallContext context);
public EntitlementEvent getEventById(final UUID eventId);
@@ -69,13 +69,13 @@ public interface EntitlementDao {
// Subscription creation, cancellation, changePlan apis
public void createSubscription(final SubscriptionData subscription, final List<EntitlementEvent> initialEvents, final CallContext context);
- public void recreateSubscription(final UUID subscriptionId, final List<EntitlementEvent> recreateEvents, final CallContext context);
+ public void recreateSubscription(final SubscriptionData subscription, final List<EntitlementEvent> recreateEvents, final CallContext context);
- public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context, final int cancelSeq);
+ public void cancelSubscription(final SubscriptionData subscription, final EntitlementEvent cancelEvent, final CallContext context, final int cancelSeq);
- public void uncancelSubscription(final UUID subscriptionId, final List<EntitlementEvent> uncancelEvents, final CallContext context);
+ public void uncancelSubscription(final SubscriptionData subscription, final List<EntitlementEvent> uncancelEvents, final CallContext context);
- public void changePlan(final UUID subscriptionId, final List<EntitlementEvent> changeEvents, final CallContext context);
+ public void changePlan(final SubscriptionData subscription, final List<EntitlementEvent> changeEvents, final CallContext context);
public void migrate(final UUID accountId, final AccountMigrationData data, final CallContext context);
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 653e1ca..ed9cf13 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
@@ -92,14 +92,15 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
}
@Override
- public void recreateSubscription(final UUID subscriptionId,
+ public void recreateSubscription(final SubscriptionData subscription,
final List<EntitlementEvent> recreateEvents, final CallContext context) {
- addEvents(subscriptionId, recreateEvents);
+ addEvents(subscription.getId(), recreateEvents);
}
@Override
- public void cancelSubscription(final UUID subscriptionId,
+ public void cancelSubscription(final SubscriptionData subscription,
final EntitlementEvent cancelEvent, final CallContext context, final int cancelSeq) {
+ final UUID subscriptionId = subscription.getId();
final long activeVersion = cancelEvent.getActiveVersion();
addEvents(subscriptionId, Collections.singletonList(cancelEvent));
final SubscriptionRepairEvent target = getRepairSubscriptionEvents(subscriptionId);
@@ -114,9 +115,9 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
}
@Override
- public void changePlan(final UUID subscriptionId,
+ public void changePlan(final SubscriptionData subscription,
final List<EntitlementEvent> changeEvents, final CallContext context) {
- addEvents(subscriptionId, changeEvents);
+ addEvents(subscription.getId(), changeEvents);
}
@Override
@@ -142,7 +143,7 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
}
@Override
- public void uncancelSubscription(final UUID subscriptionId,
+ public void uncancelSubscription(final SubscriptionData subscription,
final List<EntitlementEvent> uncancelEvents, final CallContext context) {
throw new EntitlementError(NOT_IMPLEMENTED);
}
@@ -204,7 +205,7 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
}
@Override
- public void createNextPhaseEvent(final UUID subscriptionId,
+ public void createNextPhaseEvent(final SubscriptionData subscription,
final EntitlementEvent nextPhase, final CallContext context) {
throw new EntitlementError(NOT_IMPLEMENTED);
}
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
index 400da99..6579baa 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
@@ -36,6 +36,7 @@ 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.EffectiveSubscriptionEvent;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.SubscriptionData;
import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
@@ -201,7 +202,7 @@ public class TestPlanAligner {
subscriptionData.rebuildTransitions(ImmutableList.<EntitlementEvent>of(previousEvent, event), catalogService.getFullCatalog());
- final List<SubscriptionTransitionData> newTransitions = subscriptionData.getAllTransitions();
+ final List<EffectiveSubscriptionEvent> newTransitions = subscriptionData.getAllTransitions();
Assert.assertEquals(newTransitions.size(), 2);
Assert.assertNull(newTransitions.get(0).getPreviousPhase());
Assert.assertEquals(newTransitions.get(0).getNextPhase(), newTransitions.get(1).getPreviousPhase());
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
index ec5c17e..06032f7 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
@@ -169,7 +169,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
}
@Override
- public void recreateSubscription(final UUID subscriptionId,
+ public void recreateSubscription(final SubscriptionData subscription,
final List<EntitlementEvent> recreateEvents, final CallContext context) {
synchronized (events) {
@@ -233,9 +233,9 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
}
@Override
- public void createNextPhaseEvent(final UUID subscriptionId, final EntitlementEvent nextPhase,
+ public void createNextPhaseEvent(final SubscriptionData subscription, final EntitlementEvent nextPhase,
final CallContext context) {
- cancelNextPhaseEvent(subscriptionId);
+ cancelNextPhaseEvent(subscription.getId());
insertEvent(nextPhase);
}
@@ -271,20 +271,20 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
}
@Override
- public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent,
+ public void cancelSubscription(final SubscriptionData subscription, final EntitlementEvent cancelEvent,
final CallContext context, final int seqId) {
synchronized (events) {
- cancelNextPhaseEvent(subscriptionId);
+ cancelNextPhaseEvent(subscription.getId());
insertEvent(cancelEvent);
}
}
@Override
- public void changePlan(final UUID subscriptionId, final List<EntitlementEvent> changeEvents,
+ public void changePlan(final SubscriptionData subscription, final List<EntitlementEvent> changeEvents,
final CallContext context) {
synchronized (events) {
- cancelNextChangeEvent(subscriptionId);
- cancelNextPhaseEvent(subscriptionId);
+ cancelNextChangeEvent(subscription.getId());
+ cancelNextPhaseEvent(subscription.getId());
events.addAll(changeEvents);
for (final EntitlementEvent cur : changeEvents) {
recordFutureNotificationFromTransaction(null, cur.getEffectiveDate(), new EntitlementNotificationKey(cur.getId()));
@@ -348,7 +348,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
}
@Override
- public void uncancelSubscription(final UUID subscriptionId, final List<EntitlementEvent> uncancelEvents,
+ public void uncancelSubscription(final SubscriptionData subscription, final List<EntitlementEvent> uncancelEvents,
final CallContext context) {
synchronized (events) {
@@ -356,7 +356,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
final Iterator<EntitlementEvent> it = events.descendingIterator();
while (it.hasNext()) {
final EntitlementEvent cur = it.next();
- if (cur.getSubscriptionId() != subscriptionId) {
+ if (cur.getSubscriptionId() != subscription.getId()) {
continue;
}
if (cur.getType() == EventType.API_USER &&
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
index 929f03d..6a93d3c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
@@ -24,6 +24,7 @@ import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
import com.google.inject.Inject;
+import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.entitlement.engine.addon.AddonUtils;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.clock.Clock;
@@ -35,8 +36,8 @@ public class MockEntitlementDaoSql extends AuditedEntitlementDao implements Mock
@Inject
public MockEntitlementDaoSql(final IDBI dbi, final Clock clock, final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
- final Bus eventBus) {
- super(dbi, clock, addonUtils, notificationQueueService, eventBus);
+ final Bus eventBus, final CatalogService catalogService) {
+ super(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService);
this.resetDao = dbi.onDemand(ResetSqlDao.class);
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index 38a3a74..0dec7e0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -16,6 +16,14 @@
package com.ning.billing.jaxrs.resources;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
@@ -30,11 +38,6 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -78,15 +81,13 @@ import com.ning.billing.util.api.CustomFieldUserApi;
import com.ning.billing.util.api.TagUserApi;
import com.ning.billing.util.dao.ObjectType;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-
@Singleton
@Path(JaxrsResource.ACCOUNTS_PATH)
public class AccountResource extends JaxRsResourceBase {
private static final Logger log = LoggerFactory.getLogger(AccountResource.class);
private static final String ID_PARAM_NAME = "accountId";
- private static final String CUSTOM_FIELD_URI = JaxrsResource.CUSTOM_FIELDS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
- private static final String TAG_URI = JaxrsResource.TAGS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
+ private static final String CUSTOM_FIELD_URI = JaxrsResource.CUSTOM_FIELDS;
+ private static final String TAG_URI = JaxrsResource.TAGS;
private final AccountUserApi accountApi;
private final EntitlementUserApi entitlementApi;
@@ -475,14 +476,14 @@ public class AccountResource extends JaxRsResourceBase {
*/
@GET
- @Path(CUSTOM_FIELD_URI)
+ @Path("/{accountId:" + UUID_PATTERN + "}/" + CUSTOM_FIELD_URI)
@Produces(APPLICATION_JSON)
public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id) {
return super.getCustomFields(UUID.fromString(id));
}
@POST
- @Path(CUSTOM_FIELD_URI)
+ @Path("/{accountId:" + UUID_PATTERN + "}/" + CUSTOM_FIELD_URI)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response createCustomFields(@PathParam(ID_PARAM_NAME) final String id,
@@ -495,7 +496,7 @@ public class AccountResource extends JaxRsResourceBase {
}
@DELETE
- @Path(CUSTOM_FIELD_URI)
+ @Path("/{accountId:" + UUID_PATTERN + "}/" + CUSTOM_FIELD_URI)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final String id,
@@ -512,15 +513,14 @@ public class AccountResource extends JaxRsResourceBase {
*/
@GET
- @Path(TAG_URI)
+ @Path("/{accountId:" + UUID_PATTERN + "}/" + TAG_URI)
@Produces(APPLICATION_JSON)
public Response getTags(@PathParam(ID_PARAM_NAME) final String id) {
return super.getTags(UUID.fromString(id));
}
@POST
- @Path(TAG_URI)
- @Consumes(APPLICATION_JSON)
+ @Path("/{accountId:" + UUID_PATTERN + "}/" + TAG_URI)
@Produces(APPLICATION_JSON)
public Response createTags(@PathParam(ID_PARAM_NAME) final String id,
@QueryParam(QUERY_TAGS) final String tagList,
@@ -532,7 +532,7 @@ public class AccountResource extends JaxRsResourceBase {
}
@DELETE
- @Path(TAG_URI)
+ @Path("/{accountId:" + UUID_PATTERN + "}/" + TAG_URI)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response deleteTags(@PathParam(ID_PARAM_NAME) final String id,
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
index 33d7965..5e8877c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
@@ -59,8 +59,8 @@ public class BundleResource extends JaxRsResourceBase {
private static final Logger log = LoggerFactory.getLogger(BundleResource.class);
private static final String ID_PARAM_NAME = "bundleId";
- private static final String CUSTOM_FIELD_URI = JaxrsResource.CUSTOM_FIELDS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
- private static final String TAG_URI = JaxrsResource.TAGS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
+ private static final String CUSTOM_FIELD_URI = JaxrsResource.CUSTOM_FIELDS;
+ private static final String TAG_URI = JaxrsResource.TAGS;
private final EntitlementUserApi entitlementApi;
private final Context context;
@@ -160,14 +160,14 @@ public class BundleResource extends JaxRsResourceBase {
}
@GET
- @Path(CUSTOM_FIELD_URI)
+ @Path("/{bundleId:" + UUID_PATTERN + "}/" + CUSTOM_FIELD_URI)
@Produces(APPLICATION_JSON)
public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id) {
return super.getCustomFields(UUID.fromString(id));
}
@POST
- @Path(CUSTOM_FIELD_URI)
+ @Path("/{bundleId:" + UUID_PATTERN + "}/" + CUSTOM_FIELD_URI)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response createCustomFields(@PathParam(ID_PARAM_NAME) final String id,
@@ -180,7 +180,7 @@ public class BundleResource extends JaxRsResourceBase {
}
@DELETE
- @Path(CUSTOM_FIELD_URI)
+ @Path("/{bundleId:" + UUID_PATTERN + "}/" + CUSTOM_FIELD_URI)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final String id,
@@ -193,14 +193,14 @@ public class BundleResource extends JaxRsResourceBase {
}
@GET
- @Path(TAG_URI)
+ @Path("/{bundleId:" + UUID_PATTERN + "}/" + TAG_URI)
@Produces(APPLICATION_JSON)
public Response getTags(@PathParam(ID_PARAM_NAME) final String id) {
return super.getTags(UUID.fromString(id));
}
@POST
- @Path(TAG_URI)
+ @Path("/{bundleId:" + UUID_PATTERN + "}/" + TAG_URI)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response createTags(@PathParam(ID_PARAM_NAME) final String id,
@@ -213,7 +213,7 @@ public class BundleResource extends JaxRsResourceBase {
}
@DELETE
- @Path(TAG_URI)
+ @Path("/{bundleId:" + UUID_PATTERN + "}/" + TAG_URI)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response deleteTags(@PathParam(ID_PARAM_NAME) final String id,
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 aa03560..fb41a88 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
@@ -128,6 +128,11 @@ public class BlockingSubscription implements Subscription {
return subscription.getBillingTransitions();
}
+ @Override
+ public List<EffectiveSubscriptionEvent> getAllTransitions() {
+ return subscription.getAllTransitions();
+ }
+
public BlockingState getBlockingState() {
if (blockingState == null) {
blockingState = blockingApi.getBlockingStateFor(this);
@@ -138,6 +143,4 @@ public class BlockingSubscription implements Subscription {
public Subscription getDelegateSubscription() {
return subscription;
}
-
-
}
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 ee83777..2a31a6e 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
@@ -16,7 +16,6 @@
package com.ning.billing.junction.plumbing.billing;
-
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
@@ -67,6 +66,8 @@ import com.ning.billing.junction.api.DefaultBlockingState;
import com.ning.billing.lifecycle.KillbillService.ServiceException;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.mock.MockEffectiveSubscriptionEvent;
+import com.ning.billing.mock.MockSubscription;
import com.ning.billing.util.api.TagUserApi;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.DefaultCallContextFactory;
@@ -141,7 +142,6 @@ public class TestBillingApi {
};
-
private Clock clock;
private Subscription subscription;
private DateTime subscriptionStartDate;
@@ -163,39 +163,11 @@ public class TestBillingApi {
//new SubscriptionBundleData( eventId,"TestKey", subId, clock.getUTCNow().minusDays(4), null);
bundles.add(bundle);
-
effectiveSubscriptionTransitions = new LinkedList<EffectiveSubscriptionEvent>();
final List<Subscription> subscriptions = new LinkedList<Subscription>();
subscriptionStartDate = clock.getUTCNow().minusDays(3);
- subscription = new MockSubscription() {
- @Override
- public List<EffectiveSubscriptionEvent> getBillingTransitions() {
- return effectiveSubscriptionTransitions;
- }
-
- @Override
- public Plan getCurrentPlan() {
- return subscriptionPlan;
- }
-
- @Override
- public UUID getId() {
- return subId;
- }
-
- @Override
- public UUID getBundleId() {
- return bunId;
- }
-
- @Override
- public DateTime getStartDate() {
- return subscriptionStartDate;
- }
-
-
- };
+ subscription = new MockSubscription(subId, bunId, subscriptionPlan, subscriptionStartDate, effectiveSubscriptionTransitions);
subscriptions.add(subscription);
@@ -308,7 +280,6 @@ public class TestBillingApi {
nextPriceList.getName(), 1L, null,
SubscriptionTransitionType.CREATE, 0, null);
-
effectiveSubscriptionTransitions.add(t);
final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -376,7 +347,6 @@ public class TestBillingApi {
final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
-
final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
nextPlan.getName(), nextPhase.getName(),
@@ -457,7 +427,6 @@ public class TestBillingApi {
nextPriceList.getName(), 1L, null,
SubscriptionTransitionType.CREATE, 0, null);
-
effectiveSubscriptionTransitions.add(t);
final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -486,7 +455,6 @@ public class TestBillingApi {
assertEquals(events.size(), 0);
}
-
@Test(enabled = true, groups = "fast")
public void testBillingEventsAutoInvoicingOffBundle() throws CatalogApiException {
final DateTime now = clock.getUTCNow();
@@ -501,7 +469,6 @@ public class TestBillingApi {
nextPriceList.getName(), 1L, null,
SubscriptionTransitionType.CREATE, 0, null);
-
effectiveSubscriptionTransitions.add(t);
final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
index 3e00cdd..60aa56a 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -16,13 +16,19 @@
package com.ning.billing.jaxrs;
-import javax.ws.rs.core.Response.Status;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import javax.ws.rs.core.Response.Status;
+
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,11 +49,6 @@ import com.ning.billing.jaxrs.json.TagDefinitionJson;
import com.ning.billing.jaxrs.resources.JaxrsResource;
import com.ning.http.client.Response;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
public class TestAccount extends TestJaxrsBase {
@@ -268,7 +269,7 @@ public class TestAccount extends TestJaxrsBase {
final Map<String, String> queryParams = new HashMap<String, String>();
queryParams.put(JaxrsResource.QUERY_TAGS, input.getName());
- final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + JaxrsResource.TAGS + "/" + UUID.randomUUID().toString();
+ final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + UUID.randomUUID().toString() + "/" + JaxrsResource.TAGS;
response = doPost(uri, null, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
@@ -294,7 +295,7 @@ public class TestAccount extends TestJaxrsBase {
customFields.add(new CustomFieldJson("3", "value3"));
final String baseJson = mapper.writeValueAsString(customFields);
- final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + JaxrsResource.CUSTOM_FIELDS + "/" + UUID.randomUUID().toString();
+ final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + UUID.randomUUID().toString() + "/" + JaxrsResource.CUSTOM_FIELDS;
Response response = doPost(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
diff --git a/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java b/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
index b315e79..c5e5375 100644
--- a/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
+++ b/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
@@ -171,7 +171,7 @@ public class PersistentBus extends PersistentQueueBase implements Bus {
final BusEventEntry entry = new BusEventEntry(hostname, event.getClass().getName(), json);
transactional.insertBusEvent(entry);
} catch (Exception e) {
- log.error("Failed to post BusEvent " + event.toString(), e);
+ log.error("Failed to post BusEvent " + event, e);
}
}
}
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 60da96b..0fdeeb1 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
@@ -36,6 +36,7 @@ import com.ning.billing.util.callcontext.CallContext;
public class MockEntitlementUserApi implements EntitlementUserApi {
private final Map<UUID, String> subscriptionBundles = new HashMap<UUID, String>();
private final Map<UUID, UUID> accountForBundle = new HashMap<UUID, UUID>();
+ private final Map<UUID, Subscription> subscriptionsById = new HashMap<UUID, Subscription>();
public synchronized void addBundle(final UUID bundleUUID, final String externalKey, final UUID accountId) {
subscriptionBundles.put(bundleUUID, externalKey);
diff --git a/util/src/test/java/com/ning/billing/mock/MockPriceList.java b/util/src/test/java/com/ning/billing/mock/MockPriceList.java
new file mode 100644
index 0000000..8903a3c
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/MockPriceList.java
@@ -0,0 +1,59 @@
+/*
+ * 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.mock;
+
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.Product;
+
+public class MockPriceList implements PriceList {
+ private final String name;
+ private final Boolean isRetired;
+ private final Plan plan;
+
+ public MockPriceList() {
+ this(false, UUID.randomUUID().toString(), new MockPlan());
+ }
+
+ public MockPriceList(final Boolean retired, final String name, final Plan plan) {
+ isRetired = retired;
+ this.name = name;
+ this.plan = plan;
+ }
+
+ @Override
+ public boolean isRetired() {
+ return isRetired;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Plan findPlan(final Product product, final BillingPeriod period) {
+ return plan;
+ }
+
+ public Plan getPlan() {
+ return plan;
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/mock/MockProduct.java b/util/src/test/java/com/ning/billing/mock/MockProduct.java
new file mode 100644
index 0000000..ea341b0
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/MockProduct.java
@@ -0,0 +1,107 @@
+/*
+ * 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.mock;
+
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class MockProduct implements Product {
+ private final String name;
+ private final ProductCategory category;
+ private final String catalogName;
+
+ public MockProduct() {
+ name = "TestProduct";
+ category = ProductCategory.BASE;
+ catalogName = "Vehicules";
+ }
+
+ public MockProduct(final String name, final ProductCategory category, final String catalogName) {
+ this.name = name;
+ this.category = category;
+ this.catalogName = catalogName;
+ }
+
+ @Override
+ public String getCatalogName() {
+ return catalogName;
+ }
+
+ @Override
+ public ProductCategory getCategory() {
+ return category;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isRetired() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Product[] getAvailable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Product[] getIncluded() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static MockProduct createBicycle() {
+ return new MockProduct("Bicycle", ProductCategory.BASE, "Vehcles");
+ }
+
+ public static MockProduct createPickup() {
+ return new MockProduct("Pickup", ProductCategory.BASE, "Vehcles");
+ }
+
+ public static MockProduct createSportsCar() {
+ return new MockProduct("SportsCar", ProductCategory.BASE, "Vehcles");
+ }
+
+ public static MockProduct createJet() {
+ return new MockProduct("Jet", ProductCategory.BASE, "Vehcles");
+ }
+
+ public static MockProduct createHorn() {
+ return new MockProduct("Horn", ProductCategory.ADD_ON, "Vehcles");
+ }
+
+ public static MockProduct createSpotlight() {
+ return new MockProduct("spotlight", ProductCategory.ADD_ON, "Vehcles");
+ }
+
+ public static MockProduct createRedPaintJob() {
+ return new MockProduct("RedPaintJob", ProductCategory.ADD_ON, "Vehcles");
+ }
+
+ public static Product[] createAll() {
+ return new MockProduct[]{
+ createBicycle(),
+ createPickup(),
+ createSportsCar(),
+ createJet(),
+ createHorn(),
+ createRedPaintJob()
+ };
+ }
+}