killbill-memoizeit
Changes
junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java 62(+49 -13)
Details
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index 5f70d68..6628404 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -19,6 +19,7 @@
package org.killbill.billing.junction.plumbing.billing;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import org.joda.time.DateTime;
@@ -60,7 +61,11 @@ public class BillCycleDayCalculator {
this.subscriptionApi = subscriptionApi;
}
- protected int calculateBcd(final ImmutableAccountData account, final int accountBillCycleDayLocal, final UUID bundleId, final SubscriptionBase subscription, final EffectiveSubscriptionInternalEvent transition, final InternalCallContext context)
+ private interface BCDAlignmentComputation {
+ public Integer compute() throws AccountApiException, SubscriptionBaseApiException, CatalogApiException;
+ }
+
+ protected int calculateBcd(final ImmutableAccountData account, final int accountBillCycleDayLocal, final UUID bundleId, final SubscriptionBase subscription, final EffectiveSubscriptionInternalEvent transition, final Map<UUID, Integer> bcdCache, final InternalCallContext context)
throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
final Catalog catalog = catalogService.getFullCatalog(context);
@@ -91,28 +96,49 @@ public class BillCycleDayCalculator {
phase.getPhaseType()),
transition.getRequestedTransitionTime());
- return calculateBcdForAlignment(account, accountBillCycleDayLocal, subscription, alignment, bundleId, catalog, plan, context);
+ return calculateBcdForAlignment(account, accountBillCycleDayLocal, subscription, alignment, bundleId, catalog, plan, bcdCache, context);
}
@VisibleForTesting
int calculateBcdForAlignment(final ImmutableAccountData account, final int accountBillCycleDayLocal, final SubscriptionBase subscription, final BillingAlignment alignment, final UUID bundleId,
- final Catalog catalog, final Plan plan, final InternalCallContext context) throws AccountApiException, SubscriptionBaseApiException, CatalogApiException {
- int result = 0;
+ final Catalog catalog, final Plan plan, final Map<UUID, Integer> bcdCache, final InternalCallContext context) throws AccountApiException, SubscriptionBaseApiException, CatalogApiException {
+ Integer result = 0;
+ final BCDAlignmentComputation callback;
switch (alignment) {
case ACCOUNT:
- result = accountBillCycleDayLocal != 0 ? accountBillCycleDayLocal : calculateBcdFromSubscription(subscription, plan, account, catalog, context);
+ callback = new BCDAlignmentComputation() {
+ @Override
+ public Integer compute() throws AccountApiException, SubscriptionBaseApiException, CatalogApiException {
+ return accountBillCycleDayLocal != 0 ? accountBillCycleDayLocal : calculateBcdFromSubscription(subscription, plan, account, catalog, context);
+ }
+ };
+ result = computeOrRetrieveBCDForAlignment(account.getId(), bcdCache, callback);
break;
+
case BUNDLE:
- final SubscriptionBase baseSub = subscriptionApi.getBaseSubscription(bundleId, context);
- Plan basePlan = baseSub.getCurrentPlan();
- if (basePlan == null) {
- // The BP has been cancelled
- basePlan = baseSub.getLastActivePlan();
- }
- result = calculateBcdFromSubscription(baseSub, basePlan, account, catalog, context);
+ callback = new BCDAlignmentComputation() {
+ @Override
+ public Integer compute() throws AccountApiException, SubscriptionBaseApiException, CatalogApiException {
+ final SubscriptionBase baseSub = subscriptionApi.getBaseSubscription(bundleId, context);
+ Plan basePlan = baseSub.getCurrentPlan();
+ if (basePlan == null) {
+ // The BP has been cancelled
+ basePlan = baseSub.getLastActivePlan();
+ }
+ return calculateBcdFromSubscription(baseSub, basePlan, account, catalog, context);
+ }
+ };
+ result = computeOrRetrieveBCDForAlignment(bundleId, bcdCache, callback);
break;
+
case SUBSCRIPTION:
- result = calculateBcdFromSubscription(subscription, plan, account, catalog, context);
+ callback = new BCDAlignmentComputation() {
+ @Override
+ public Integer compute() throws AccountApiException, SubscriptionBaseApiException, CatalogApiException {
+ return calculateBcdFromSubscription(subscription, plan, account, catalog, context);
+ }
+ };
+ result = computeOrRetrieveBCDForAlignment(subscription.getId(), bcdCache, callback);
break;
}
@@ -123,6 +149,16 @@ public class BillCycleDayCalculator {
return result;
}
+
+ int computeOrRetrieveBCDForAlignment(final UUID objectId, final Map<UUID, Integer> bcdCache, final BCDAlignmentComputation callback) throws AccountApiException, CatalogApiException, SubscriptionBaseApiException {
+ Integer result = bcdCache.get(objectId);
+ if (result == null) {
+ result = callback.compute();
+ bcdCache.put(objectId, result);
+ }
+ return result;
+ }
+
@VisibleForTesting
int calculateBcdFromSubscription(final SubscriptionBase subscription, final Plan plan, final ImmutableAccountData account, final Catalog catalog, final InternalCallContext context)
throws AccountApiException, CatalogApiException {
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index ff1e3f4..c67962c 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -18,8 +18,10 @@
package org.killbill.billing.junction.plumbing.billing;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.UUID;
@@ -170,6 +172,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
// If dryRun is specified, we don't want to to update the account BCD value, so we initialize the flag updatedAccountBCD to true
boolean updatedAccountBCD = dryRunMode;
+ final Map<UUID, Integer> bcdCache =new HashMap<UUID, Integer>();
int currentAccountBCD = accountApi.getBCD(account.getId(), context);
for (final SubscriptionBase subscription : subscriptions) {
@@ -191,7 +194,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
}
for (final EffectiveSubscriptionInternalEvent transition : billingTransitions) {
- final int bcdLocal = bcdCalculator.calculateBcd(account, currentAccountBCD, bundleId, subscription, transition, context);
+ final int bcdLocal = bcdCalculator.calculateBcd(account, currentAccountBCD, bundleId, subscription, transition, bcdCache, context);
if (currentAccountBCD == 0 && !updatedAccountBCD) {
accountApi.updateBCD(account.getExternalKey(), bcdLocal, context);
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
index adef503..aa0d2e8 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
@@ -16,6 +16,7 @@
package org.killbill.billing.junction.plumbing.billing;
+import java.util.HashMap;
import java.util.UUID;
import org.joda.time.DateTime;
@@ -63,7 +64,7 @@ public class TestBillCycleDayCalculator extends JunctionTestSuiteNoDB {
final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
final Integer billCycleDayLocal = billCycleDayCalculator.calculateBcdForAlignment(account, 0, subscription, BillingAlignment.BUNDLE, bundle.getId(),
- catalog, null, internalCallContext);
+ catalog, null, new HashMap<UUID, Integer>(), internalCallContext);
Assert.assertEquals(billCycleDayLocal, (Integer) expectedBCDUTC);
}