killbill-memoizeit
Changes
account/pom.xml 2(+1 -1)
api/pom.xml 2(+1 -1)
beatrix/pom.xml 2(+1 -1)
catalog/pom.xml 2(+1 -1)
currency/pom.xml 2(+1 -1)
entitlement/pom.xml 2(+1 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java 268(+117 -151)
entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java 754(+379 -375)
entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultAccountEntitlements.java 90(+90 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultAccountEventsStreams.java 108(+108 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java 101(+101 -0)
entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java 39(+22 -17)
entitlement/src/main/java/com/ning/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java 75(+75 -0)
entitlement/src/main/java/com/ning/billing/entitlement/engine/core/DefaultEventsStream.java 153(+125 -28)
entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventsStreamBuilder.java 218(+189 -29)
entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java 50(+46 -4)
entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java 3(+3 -0)
invoice/pom.xml 2(+1 -1)
jaxrs/pom.xml 2(+1 -1)
jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionBillingApiExceptionMapper.java 2(+1 -1)
junction/pom.xml 2(+1 -1)
junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java 3(+3 -0)
osgi/pom.xml 2(+1 -1)
osgi-bundles/bundles/jruby/pom.xml 2(+1 -1)
osgi-bundles/bundles/logger/pom.xml 2(+1 -1)
osgi-bundles/bundles/pom.xml 2(+1 -1)
osgi-bundles/defaultbundles/pom.xml 2(+1 -1)
osgi-bundles/libs/killbill/pom.xml 2(+1 -1)
osgi-bundles/libs/pom.xml 2(+1 -1)
osgi-bundles/libs/slf4j-osgi/pom.xml 2(+1 -1)
osgi-bundles/pom.xml 2(+1 -1)
osgi-bundles/tests/beatrix/pom.xml 2(+1 -1)
osgi-bundles/tests/payment/pom.xml 2(+1 -1)
osgi-bundles/tests/pom.xml 2(+1 -1)
overdue/pom.xml 2(+1 -1)
payment/pom.xml 2(+1 -1)
pom.xml 2(+1 -1)
server/pom.xml 2(+1 -1)
subscription/pom.xml 2(+1 -1)
subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java 160(+92 -68)
subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java 4(+1 -3)
tenant/pom.xml 2(+1 -1)
usage/pom.xml 2(+1 -1)
util/pom.xml 2(+1 -1)
Details
account/pom.xml 2(+1 -1)
diff --git a/account/pom.xml b/account/pom.xml
index a66537e..f63d185 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-account</artifactId>
api/pom.xml 2(+1 -1)
diff --git a/api/pom.xml b/api/pom.xml
index fed08a0..31ad402 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-internal-api</artifactId>
diff --git a/api/src/main/java/com/ning/billing/entitlement/AccountEntitlements.java b/api/src/main/java/com/ning/billing/entitlement/AccountEntitlements.java
new file mode 100644
index 0000000..3a192e9
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/entitlement/AccountEntitlements.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.UUID;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.entitlement.api.Entitlement;
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+
+// Wrapper object to save on DAO calls
+public interface AccountEntitlements {
+
+ public Account getAccount();
+
+ // Map bundle id -> bundle
+ public Map<UUID, SubscriptionBaseBundle> getBundles();
+
+ // Map bundle id -> entitlements
+ public Map<UUID, Collection<Entitlement>> getEntitlements();
+}
diff --git a/api/src/main/java/com/ning/billing/entitlement/AccountEventsStreams.java b/api/src/main/java/com/ning/billing/entitlement/AccountEventsStreams.java
new file mode 100644
index 0000000..94e7817
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/entitlement/AccountEventsStreams.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.UUID;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+
+// Wrapper object to save on DAO calls
+public interface AccountEventsStreams {
+
+ public Account getAccount();
+
+ // Map bundle id -> bundle
+ public Map<UUID, SubscriptionBaseBundle> getBundles();
+
+ // Map bundle id -> events streams
+ public Map<UUID, Collection<EventsStream>> getEventsStreams();
+}
diff --git a/api/src/main/java/com/ning/billing/entitlement/EntitlementInternalApi.java b/api/src/main/java/com/ning/billing/entitlement/EntitlementInternalApi.java
new file mode 100644
index 0000000..44953ea
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/entitlement/EntitlementInternalApi.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement;
+
+import java.util.UUID;
+
+import com.ning.billing.entitlement.api.EntitlementApiException;
+import com.ning.billing.util.callcontext.TenantContext;
+
+public interface EntitlementInternalApi {
+
+ public AccountEntitlements getAllEntitlementsForAccountId(UUID accountId, TenantContext context) throws EntitlementApiException;
+}
diff --git a/api/src/main/java/com/ning/billing/entitlement/EventsStream.java b/api/src/main/java/com/ning/billing/entitlement/EventsStream.java
new file mode 100644
index 0000000..fc57b74
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/entitlement/EventsStream.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement;
+
+import java.util.Collection;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+
+import com.ning.billing.callcontext.InternalTenantContext;
+import com.ning.billing.entitlement.api.BlockingState;
+import com.ning.billing.entitlement.api.Entitlement.EntitlementState;
+import com.ning.billing.subscription.api.SubscriptionBase;
+
+public interface EventsStream {
+
+ UUID getAccountId();
+
+ DateTimeZone getAccountTimeZone();
+
+ UUID getBundleId();
+
+ String getBundleExternalKey();
+
+ UUID getEntitlementId();
+
+ EntitlementState getEntitlementState();
+
+ LocalDate getEntitlementEffectiveEndDate();
+
+ SubscriptionBase getSubscription();
+
+ SubscriptionBase getBaseSubscription();
+
+ boolean isEntitlementActive();
+
+ boolean isBlockChange();
+
+ boolean isEntitlementCancelled();
+
+ boolean isSubscriptionCancelled();
+
+ Collection<BlockingState> getCurrentSubscriptionEntitlementBlockingStatesForServices();
+
+ Collection<BlockingState> getPendingEntitlementCancellationEvents();
+
+ Collection<BlockingState> getSubscriptionEntitlementStates();
+
+ Collection<BlockingState> getBundleEntitlementStates();
+
+ Collection<BlockingState> getAccountEntitlementStates();
+
+ Collection<BlockingState> computeAddonsBlockingStatesForNextSubscriptionBaseEvent(DateTime effectiveDate);
+
+ Collection<BlockingState> computeAddonsBlockingStatesForFutureSubscriptionBaseEvents();
+
+ InternalTenantContext getInternalTenantContext();
+}
diff --git a/api/src/main/java/com/ning/billing/glue/EntitlementModule.java b/api/src/main/java/com/ning/billing/glue/EntitlementModule.java
index 456fb17..bd21d81 100644
--- a/api/src/main/java/com/ning/billing/glue/EntitlementModule.java
+++ b/api/src/main/java/com/ning/billing/glue/EntitlementModule.java
@@ -17,12 +17,15 @@
package com.ning.billing.glue;
public interface EntitlementModule {
+
public void installBlockingStateDao();
public void installBlockingApi();
public void installEntitlementApi();
+ public void installEntitlementInternalApi();
+
public void installSubscriptionApi();
public void installBlockingChecker();
diff --git a/api/src/main/java/com/ning/billing/glue/SubscriptionModule.java b/api/src/main/java/com/ning/billing/glue/SubscriptionModule.java
index a400b68..65185eb 100644
--- a/api/src/main/java/com/ning/billing/glue/SubscriptionModule.java
+++ b/api/src/main/java/com/ning/billing/glue/SubscriptionModule.java
@@ -27,5 +27,4 @@ public interface SubscriptionModule {
public void installSubscriptionInternalApi();
public void installSubscriptionTimelineApi();
-
}
beatrix/pom.xml 2(+1 -1)
diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index caa12bb..5518181 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-beatrix</artifactId>
catalog/pom.xml 2(+1 -1)
diff --git a/catalog/pom.xml b/catalog/pom.xml
index 011fe1d..fd8864e 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-catalog</artifactId>
currency/pom.xml 2(+1 -1)
diff --git a/currency/pom.xml b/currency/pom.xml
index e3e6379..003458b 100644
--- a/currency/pom.xml
+++ b/currency/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
entitlement/pom.xml 2(+1 -1)
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 1540e00..7e53f2f 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-entitlement</artifactId>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
index 983381d..ac479f7 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
@@ -21,10 +21,10 @@ import java.util.Collection;
import java.util.UUID;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import com.ning.billing.ErrorCode;
-import com.ning.billing.account.api.Account;
import com.ning.billing.callcontext.InternalCallContext;
import com.ning.billing.catalog.api.BillingActionPolicy;
import com.ning.billing.catalog.api.BillingPeriod;
@@ -36,12 +36,12 @@ import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.clock.Clock;
import com.ning.billing.entitlement.DefaultEntitlementService;
import com.ning.billing.entitlement.EntitlementService;
+import com.ning.billing.entitlement.EventsStream;
import com.ning.billing.entitlement.block.BlockingChecker;
import com.ning.billing.entitlement.dao.BlockingStateDao;
import com.ning.billing.entitlement.engine.core.EntitlementNotificationKey;
import com.ning.billing.entitlement.engine.core.EntitlementNotificationKeyAction;
import com.ning.billing.entitlement.engine.core.EntitlementUtils;
-import com.ning.billing.entitlement.engine.core.EventsStream;
import com.ning.billing.entitlement.engine.core.EventsStreamBuilder;
import com.ning.billing.entity.EntityBase;
import com.ning.billing.junction.DefaultBlockingState;
@@ -88,7 +88,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
final SubscriptionBaseInternalApi subscriptionInternalApi, final BlockingChecker checker,
final NotificationQueueService notificationQueueService, final EntitlementUtils entitlementUtils,
final EntitlementDateHelper dateHelper, final Clock clock, final InternalCallContextFactory internalCallContextFactory) {
- super(eventsStream.getSubscription().getId(), eventsStream.getSubscription().getCreatedDate(), eventsStream.getSubscription().getUpdatedDate());
+ super(eventsStream.getEntitlementId(), eventsStream.getSubscription().getCreatedDate(), eventsStream.getSubscription().getUpdatedDate());
this.eventsStreamBuilder = eventsStreamBuilder;
this.eventsStream = eventsStream;
this.dateHelper = dateHelper;
@@ -116,18 +116,22 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
in.getInternalCallContextFactory());
}
- public Account getAccount() {
- return eventsStream.getAccount();
- }
-
public EventsStream getEventsStream() {
return eventsStream;
}
+ public DateTimeZone getAccountTimeZone() {
+ return eventsStream.getAccountTimeZone();
+ }
+
public SubscriptionBase getSubscriptionBase() {
return eventsStream.getSubscription();
}
+ public SubscriptionBase getBaseSubscription() {
+ return eventsStream.getBaseSubscription();
+ }
+
public EventsStreamBuilder getEventsStreamBuilder() {
return eventsStreamBuilder;
}
@@ -170,22 +174,22 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
@Override
public UUID getBaseEntitlementId() {
- return eventsStream.getSubscription().getId();
+ return eventsStream.getEntitlementId();
}
@Override
public UUID getBundleId() {
- return eventsStream.getSubscription().getBundleId();
+ return eventsStream.getBundleId();
}
@Override
public UUID getAccountId() {
- return eventsStream.getAccount().getId();
+ return eventsStream.getAccountId();
}
@Override
public String getExternalKey() {
- return eventsStream.getBundle().getExternalKey();
+ return eventsStream.getBundleExternalKey();
}
@Override
@@ -200,7 +204,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
@Override
public LocalDate getEffectiveStartDate() {
- return new LocalDate(getSubscriptionBase().getStartDate(), eventsStream.getAccount().getTimeZone());
+ return new LocalDate(getSubscriptionBase().getStartDate(), eventsStream.getAccountTimeZone());
}
@Override
@@ -319,7 +323,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// (we don't want an entitlement cancel date one second or so after the subscription cancel date or add-ons cancellations
// computations won't work).
final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(getAccountId(), callContext);
- final LocalDate effectiveLocalDate = new LocalDate(localCancelDate, eventsStream.getAccount().getTimeZone());
+ final LocalDate effectiveLocalDate = new LocalDate(localCancelDate, eventsStream.getAccountTimeZone());
final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(effectiveLocalDate, getSubscriptionBase().getStartDate(), contextWithValidAccountRecordId);
try {
@@ -341,10 +345,10 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
final LocalDate cancellationDate;
switch (entitlementPolicy) {
case IMMEDIATE:
- cancellationDate = new LocalDate(clock.getUTCNow(), eventsStream.getAccount().getTimeZone());
+ cancellationDate = new LocalDate(clock.getUTCNow(), eventsStream.getAccountTimeZone());
break;
case END_OF_TERM:
- cancellationDate = getSubscriptionBase().getChargedThroughDate() != null ? new LocalDate(getSubscriptionBase().getChargedThroughDate(), eventsStream.getAccount().getTimeZone()) : new LocalDate(clock.getUTCNow(), eventsStream.getAccount().getTimeZone());
+ cancellationDate = getSubscriptionBase().getChargedThroughDate() != null ? new LocalDate(getSubscriptionBase().getChargedThroughDate(), eventsStream.getAccountTimeZone()) : new LocalDate(clock.getUTCNow(), eventsStream.getAccountTimeZone());
break;
default:
throw new RuntimeException("Unsupported policy " + entitlementPolicy);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
index 5be1c0e..dfd9cd6 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
@@ -17,9 +17,7 @@
package com.ning.billing.entitlement.api;
import java.io.IOException;
-import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
@@ -41,15 +39,16 @@ import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.catalog.api.BillingActionPolicy;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.AccountEventsStreams;
import com.ning.billing.entitlement.DefaultEntitlementService;
import com.ning.billing.entitlement.EntitlementService;
import com.ning.billing.entitlement.EntitlementTransitionType;
+import com.ning.billing.entitlement.EventsStream;
import com.ning.billing.entitlement.block.BlockingChecker;
import com.ning.billing.entitlement.dao.BlockingStateDao;
import com.ning.billing.entitlement.engine.core.EntitlementNotificationKey;
import com.ning.billing.entitlement.engine.core.EntitlementNotificationKeyAction;
import com.ning.billing.entitlement.engine.core.EntitlementUtils;
-import com.ning.billing.entitlement.engine.core.EventsStream;
import com.ning.billing.entitlement.engine.core.EventsStreamBuilder;
import com.ning.billing.junction.DefaultBlockingState;
import com.ning.billing.notificationq.api.NotificationEvent;
@@ -141,8 +140,8 @@ public class DefaultEntitlementApi implements EntitlementApi {
}
// Check the base entitlement state is not blocked
- if (eventsStreamForBaseSubscription.getCurrentBlockingAggregator().isBlockChange()) {
- throw new EntitlementApiException(new BlockingApiException(ErrorCode.BLOCK_BLOCKED_ACTION, BlockingChecker.ACTION_CHANGE, BlockingChecker.TYPE_SUBSCRIPTION, eventsStreamForBaseSubscription.getSubscription().getId().toString()));
+ if (eventsStreamForBaseSubscription.isBlockChange()) {
+ throw new EntitlementApiException(new BlockingApiException(ErrorCode.BLOCK_BLOCKED_ACTION, BlockingChecker.ACTION_CHANGE, BlockingChecker.TYPE_SUBSCRIPTION, eventsStreamForBaseSubscription.getEntitlementId().toString()));
}
final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(effectiveDate, eventsStreamForBaseSubscription.getSubscription().getStartDate(), eventsStreamForBaseSubscription.getInternalTenantContext());
@@ -184,8 +183,21 @@ public class DefaultEntitlementApi implements EntitlementApi {
@Override
public List<Entitlement> getAllEntitlementsForBundle(final UUID bundleId, final TenantContext tenantContext) throws EntitlementApiException {
- final InternalTenantContext context = internalCallContextFactory.createInternalTenantContext(tenantContext);
- return getAllEntitlementsForBundle(subscriptionInternalApi.getSubscriptionsForBundle(bundleId, context), tenantContext);
+ final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(tenantContext);
+ final UUID accountId;
+ try {
+ accountId = subscriptionInternalApi.getBundleFromId(bundleId, internalContext).getAccountId();
+ } catch (SubscriptionBaseApiException e) {
+ throw new EntitlementApiException(e);
+ }
+
+ return ImmutableList.<Entitlement>copyOf(Iterables.<Entitlement>filter(getAllEntitlementsForAccountId(accountId, tenantContext),
+ new Predicate<Entitlement>() {
+ @Override
+ public boolean apply(final Entitlement input) {
+ return bundleId.equals(input.getBundleId());
+ }
+ }));
}
@Override
@@ -202,29 +214,20 @@ public class DefaultEntitlementApi implements EntitlementApi {
@Override
public List<Entitlement> getAllEntitlementsForAccountId(final UUID accountId, final TenantContext tenantContext) throws EntitlementApiException {
+ final EntitlementApi entitlementApi = this;
final InternalTenantContext context = internalCallContextFactory.createInternalTenantContext(accountId, tenantContext);
- final Map<UUID, List<SubscriptionBase>> subscriptionsPerBundle = subscriptionInternalApi.getSubscriptionsForAccount(context);
-
- final List<Entitlement> result = new LinkedList<Entitlement>();
- for (final UUID bundleId : subscriptionsPerBundle.keySet()) {
- final List<Entitlement> entitlements = getAllEntitlementsForBundle(subscriptionsPerBundle.get(bundleId), tenantContext);
- result.addAll(entitlements);
- }
- return result;
- }
- private List<Entitlement> getAllEntitlementsForBundle(final List<SubscriptionBase> subscriptions, final TenantContext context) {
- return Lists.transform(subscriptions,
- new Function<SubscriptionBase, Entitlement>() {
- @Override
- public Entitlement apply(final SubscriptionBase input) {
- try {
- return getEntitlementForId(input.getId(), context);
- } catch (EntitlementApiException e) {
- throw new RuntimeException("Failed to extract blocking state for subscription " + input.getId().toString());
- }
- }
- });
+ final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(context);
+ final List<EventsStream> eventsStreams = ImmutableList.<EventsStream>copyOf(Iterables.<EventsStream>concat(accountEventsStreams.getEventsStreams().values()));
+ return Lists.<EventsStream, Entitlement>transform(eventsStreams,
+ new Function<EventsStream, Entitlement>() {
+ @Override
+ public Entitlement apply(final EventsStream eventsStream) {
+ return new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi,
+ blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
+ entitlementUtils, dateHelper, clock, internalCallContextFactory);
+ }
+ });
}
@Override
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscription.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscription.java
index 25842b7..3938659 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscription.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscription.java
@@ -16,29 +16,32 @@
package com.ning.billing.entitlement.api;
-import java.util.List;
+import java.util.Collection;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
public class DefaultSubscription extends DefaultEntitlement implements Subscription {
- private final List<BlockingState> blockingStates;
+ private final Collection<BlockingState> currentSubscriptionBlockingStatesForServices;
- DefaultSubscription(final DefaultEntitlement entitlement, final List<BlockingState> blockingStates) {
+ DefaultSubscription(final DefaultEntitlement entitlement) {
super(entitlement);
- this.blockingStates = blockingStates;
+ this.currentSubscriptionBlockingStatesForServices = eventsStream.getCurrentSubscriptionEntitlementBlockingStatesForServices();
}
@Override
public LocalDate getBillingStartDate() {
- return new LocalDate(getSubscriptionBase().getStartDate(), getAccount().getTimeZone());
+ return new LocalDate(getSubscriptionBase().getStartDate(), getAccountTimeZone());
}
@Override
public LocalDate getBillingEndDate() {
final DateTime futureOrCurrentEndDateForSubscription = getSubscriptionBase().getEndDate() != null ? getSubscriptionBase().getEndDate() : getSubscriptionBase().getFutureEndDate();
- final DateTime futureOrCurrentEndDateForBaseSubscription = getEventsStream().getBaseSubscription().getEndDate() != null ? getEventsStream().getBaseSubscription().getEndDate() : getEventsStream().getBaseSubscription().getFutureEndDate();
+ final DateTime futureOrCurrentEndDateForBaseSubscription = getBaseSubscription().getEndDate() != null ? getBaseSubscription().getEndDate() : getBaseSubscription().getFutureEndDate();
final DateTime futureOrCurrentEndDate;
if (futureOrCurrentEndDateForBaseSubscription != null && futureOrCurrentEndDateForBaseSubscription.isBefore(futureOrCurrentEndDateForSubscription)) {
@@ -47,25 +50,27 @@ public class DefaultSubscription extends DefaultEntitlement implements Subscript
futureOrCurrentEndDate = futureOrCurrentEndDateForSubscription;
}
- return futureOrCurrentEndDate != null ? new LocalDate(futureOrCurrentEndDate, getAccount().getTimeZone()) : null;
+ return futureOrCurrentEndDate != null ? new LocalDate(futureOrCurrentEndDate, getAccountTimeZone()) : null;
}
@Override
public LocalDate getChargedThroughDate() {
- return getSubscriptionBase().getChargedThroughDate() != null ? new LocalDate(getSubscriptionBase().getChargedThroughDate(), getAccount().getTimeZone()) : null;
+ return getSubscriptionBase().getChargedThroughDate() != null ? new LocalDate(getSubscriptionBase().getChargedThroughDate(), getAccountTimeZone()) : null;
}
@Override
public String getCurrentStateForService(final String serviceName) {
-
- if (blockingStates == null) {
+ if (currentSubscriptionBlockingStatesForServices == null) {
return null;
+ } else {
+ final BlockingState blockingState = Iterables.<BlockingState>tryFind(currentSubscriptionBlockingStatesForServices,
+ new Predicate<BlockingState>() {
+ @Override
+ public boolean apply(final BlockingState input) {
+ return serviceName.equals(input.getService());
+ }
+ }).orNull();
+ return blockingState == null ? null : blockingState.getService();
}
- for (BlockingState cur : blockingStates) {
- if (cur.getService().equals(serviceName)) {
- return cur.getStateName();
- }
- }
- return null;
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java
index 850317f..d3b480e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -17,11 +17,10 @@
package com.ning.billing.entitlement.api;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
+import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
@@ -29,217 +28,184 @@ import javax.inject.Inject;
import org.joda.time.DateTimeZone;
import com.ning.billing.ErrorCode;
-import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountApiException;
-import com.ning.billing.account.api.AccountInternalApi;
+import com.ning.billing.ObjectType;
import com.ning.billing.callcontext.InternalTenantContext;
-import com.ning.billing.clock.Clock;
-import com.ning.billing.entitlement.block.BlockingChecker;
-import com.ning.billing.entitlement.dao.BlockingStateDao;
+import com.ning.billing.entitlement.AccountEntitlements;
+import com.ning.billing.entitlement.EntitlementInternalApi;
import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.callcontext.TenantContext;
+import com.ning.billing.util.customfield.ShouldntHappenException;
+import com.ning.billing.util.dao.NonEntityDao;
-import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.ListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
public class DefaultSubscriptionApi implements SubscriptionApi {
+ private final EntitlementInternalApi entitlementInternalApi;
private final SubscriptionBaseInternalApi subscriptionInternalApi;
- private final EntitlementApi entitlementApi;
- private final BlockingChecker checker;
- private final BlockingStateDao blockingStateDao;
- private final EntitlementDateHelper dateHelper;
- private final Clock clock;
private final InternalCallContextFactory internalCallContextFactory;
- private final AccountInternalApi accountApi;
+ private final NonEntityDao nonEntityDao;
+ private final CacheControllerDispatcher cacheControllerDispatcher;
@Inject
- public DefaultSubscriptionApi(final SubscriptionBaseInternalApi subscriptionInternalApi, final EntitlementApi entitlementApi, final BlockingChecker checker, final BlockingStateDao blockingStateDao, final AccountInternalApi accountApi, final Clock clock, final InternalCallContextFactory internalCallContextFactory) {
+ public DefaultSubscriptionApi(final EntitlementInternalApi entitlementInternalApi, final SubscriptionBaseInternalApi subscriptionInternalApi,
+ final InternalCallContextFactory internalCallContextFactory, final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
+ this.entitlementInternalApi = entitlementInternalApi;
this.subscriptionInternalApi = subscriptionInternalApi;
- this.entitlementApi = entitlementApi;
- this.accountApi = accountApi;
- this.checker = checker;
- this.blockingStateDao = blockingStateDao;
- this.dateHelper = new EntitlementDateHelper(accountApi, clock);
- ;
- this.clock = clock;
this.internalCallContextFactory = internalCallContextFactory;
+ this.nonEntityDao = nonEntityDao;
+ this.cacheControllerDispatcher = cacheControllerDispatcher;
}
@Override
public Subscription getSubscriptionForEntitlementId(final UUID entitlementId, final TenantContext context) throws SubscriptionApiException {
+ final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(entitlementId, ObjectType.SUBSCRIPTION, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
+ final UUID accountId = nonEntityDao.retrieveIdFromObject(accountRecordId, ObjectType.ACCOUNT);
+
+ // Retrieve entitlements
+ final AccountEntitlements accountEntitlements;
try {
- final Entitlement entitlement = entitlementApi.getEntitlementForId(entitlementId, context);
- final InternalTenantContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(entitlement.getAccountId(), context);
- return fromEntitlement(entitlement, contextWithValidAccountRecordId);
+ accountEntitlements = entitlementInternalApi.getAllEntitlementsForAccountId(accountId, context);
} catch (EntitlementApiException e) {
throw new SubscriptionApiException(e);
}
+
+ // Build subscriptions
+ final Iterable<Subscription> accountSubscriptions = Iterables.<Subscription>concat(buildSubscriptionsFromEntitlements(accountEntitlements).values());
+
+ return Iterables.<Subscription>find(accountSubscriptions,
+ new Predicate<Subscription>() {
+ @Override
+ public boolean apply(final Subscription subscription) {
+ return subscription.getId().equals(entitlementId);
+ }
+ });
}
@Override
public SubscriptionBundle getSubscriptionBundle(final UUID bundleId, final TenantContext context) throws SubscriptionApiException {
-
- try {
-
- final List<Entitlement> entitlements = entitlementApi.getAllEntitlementsForBundle(bundleId, context);
- if (entitlements.isEmpty()) {
- throw new SubscriptionApiException(ErrorCode.SUB_GET_INVALID_BUNDLE_ID, bundleId);
- }
- return getSubscriptionBundleFromEntitlements(bundleId, entitlements, context);
- } catch (EntitlementApiException e) {
- throw new SubscriptionApiException(e);
- } catch (SubscriptionBaseApiException e) {
- throw new SubscriptionApiException(e);
- } catch (AccountApiException e) {
- throw new SubscriptionApiException(e);
+ final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(bundleId, ObjectType.BUNDLE, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
+ final UUID accountId = nonEntityDao.retrieveIdFromObject(accountRecordId, ObjectType.ACCOUNT);
+
+ final Optional<SubscriptionBundle> bundleOptional = Iterables.<SubscriptionBundle>tryFind(getSubscriptionBundlesForAccount(accountId, context),
+ new Predicate<SubscriptionBundle>() {
+ @Override
+ public boolean apply(final SubscriptionBundle bundle) {
+ return bundle.getId().equals(bundleId);
+ }
+ });
+ if (!bundleOptional.isPresent()) {
+ throw new SubscriptionApiException(ErrorCode.SUB_GET_INVALID_BUNDLE_ID, bundleId);
+ } else {
+ return bundleOptional.get();
}
}
-
@Override
public List<SubscriptionBundle> getSubscriptionBundlesForAccountIdAndExternalKey(final UUID accountId, final String externalKey, final TenantContext context) throws SubscriptionApiException {
-
- try {
-
- final List<Entitlement> entitlements = entitlementApi.getAllEntitlementsForAccountIdAndExternalKey(accountId, externalKey, context);
- if (entitlements.isEmpty()) {
- throw new SubscriptionApiException(ErrorCode.SUB_GET_INVALID_BUNDLE_KEY, externalKey);
- }
- return getSubscriptionBundles(entitlements, context);
- } catch (EntitlementApiException e) {
- throw new SubscriptionApiException(e);
- } catch (SubscriptionBaseApiException e) {
- throw new SubscriptionApiException(e);
- } catch (AccountApiException e) {
- throw new SubscriptionApiException(e);
- }
+ return ImmutableList.<SubscriptionBundle>copyOf(Iterables.<SubscriptionBundle>filter(getSubscriptionBundlesForAccount(accountId, context),
+ new Predicate<SubscriptionBundle>() {
+ @Override
+ public boolean apply(final SubscriptionBundle bundle) {
+ return bundle.getExternalKey().equals(externalKey);
+ }
+ }));
}
@Override
- public SubscriptionBundle getActiveSubscriptionBundleForExternalKey(final String externalKey,
- final TenantContext context) throws SubscriptionApiException {
-
+ public SubscriptionBundle getActiveSubscriptionBundleForExternalKey(final String externalKey, final TenantContext context) throws SubscriptionApiException {
final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(context);
try {
final SubscriptionBaseBundle baseBundle = subscriptionInternalApi.getActiveBundleForKey(externalKey, internalContext);
- final List<Entitlement> allEntitlementsForBundle = entitlementApi.getAllEntitlementsForBundle(baseBundle.getId(), context);
-
- return getSubscriptionBundleFromEntitlements(baseBundle.getId(), allEntitlementsForBundle, context);
+ return getSubscriptionBundle(baseBundle.getId(), context);
} catch (SubscriptionBaseApiException e) {
throw new SubscriptionApiException(e);
- } catch (EntitlementApiException e) {
- throw new SubscriptionApiException(e);
- } catch (AccountApiException e) {
- throw new SubscriptionApiException(e);
}
}
@Override
public List<SubscriptionBundle> getSubscriptionBundlesForExternalKey(final String externalKey, final TenantContext context) throws SubscriptionApiException {
-
final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(context);
- try {
- final List<SubscriptionBaseBundle> baseBundles = subscriptionInternalApi.getBundlesForKey(externalKey, internalContext);
- final List<SubscriptionBundle> result = new ArrayList<SubscriptionBundle>(baseBundles.size());
- for (SubscriptionBaseBundle cur : baseBundles) {
- final List<Entitlement> allEntitlementsForBundle = entitlementApi.getAllEntitlementsForBundle(cur.getId(), context);
- final SubscriptionBundle bundle = getSubscriptionBundleFromEntitlements(cur.getId(), allEntitlementsForBundle, context);
- result.add(bundle);
- }
- return result;
- } catch (SubscriptionBaseApiException e) {
- throw new SubscriptionApiException(e);
- } catch (EntitlementApiException e) {
- throw new SubscriptionApiException(e);
- } catch (AccountApiException e) {
- throw new SubscriptionApiException(e);
+ final List<SubscriptionBaseBundle> baseBundles = subscriptionInternalApi.getBundlesForKey(externalKey, internalContext);
+
+ final List<SubscriptionBundle> result = new ArrayList<SubscriptionBundle>(baseBundles.size());
+ for (final SubscriptionBaseBundle cur : baseBundles) {
+ final SubscriptionBundle bundle = getSubscriptionBundle(cur.getId(), context);
+ result.add(bundle);
}
+
+ return result;
}
@Override
- public List<SubscriptionBundle> getSubscriptionBundlesForAccountId(final UUID accountId,
- final TenantContext context) throws SubscriptionApiException {
- try {
+ public List<SubscriptionBundle> getSubscriptionBundlesForAccountId(final UUID accountId, final TenantContext context) throws SubscriptionApiException {
+ return getSubscriptionBundlesForAccount(accountId, context);
+ }
- final List<Entitlement> entitlements = entitlementApi.getAllEntitlementsForAccountId(accountId, context);
- if (entitlements.isEmpty()) {
- return Collections.emptyList();
- }
- return getSubscriptionBundles(entitlements, context);
+ private List<SubscriptionBundle> getSubscriptionBundlesForAccount(final UUID accountId, final TenantContext tenantContext) throws SubscriptionApiException {
+ // Retrieve entitlements
+ final AccountEntitlements accountEntitlements;
+ try {
+ accountEntitlements = entitlementInternalApi.getAllEntitlementsForAccountId(accountId, tenantContext);
} catch (EntitlementApiException e) {
throw new SubscriptionApiException(e);
- } catch (SubscriptionBaseApiException e) {
- throw new SubscriptionApiException(e);
- } catch (AccountApiException e) {
- throw new SubscriptionApiException(e);
}
- }
- private List<SubscriptionBundle> getSubscriptionBundles(final List<Entitlement> entitlements, final TenantContext context) throws SubscriptionBaseApiException, AccountApiException {
- final ListMultimap<UUID, Entitlement> perBundleEntitlements = LinkedListMultimap.create();
- for (Entitlement cur : entitlements) {
- perBundleEntitlements.put(cur.getBundleId(), cur);
+ // Build subscriptions
+ final Map<UUID, List<Subscription>> subscriptionsPerBundle = buildSubscriptionsFromEntitlements(accountEntitlements);
+
+ final DateTimeZone accountTimeZone = accountEntitlements.getAccount().getTimeZone();
+
+ // Build subscription bundles
+ final List<SubscriptionBundle> bundles = new LinkedList<SubscriptionBundle>();
+ for (final UUID bundleId : subscriptionsPerBundle.keySet()) {
+ final List<Subscription> subscriptionsForBundle = subscriptionsPerBundle.get(bundleId);
+ final String externalKey = subscriptionsForBundle.get(0).getExternalKey();
+
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone,
+ accountId,
+ bundleId,
+ externalKey,
+ accountEntitlements.getEntitlements().get(bundleId));
+
+ final SubscriptionBaseBundle baseBundle = accountEntitlements.getBundles().get(bundleId);
+ final SubscriptionBundle subscriptionBundle = new DefaultSubscriptionBundle(bundleId,
+ accountId,
+ externalKey,
+ subscriptionsForBundle,
+ timeline,
+ baseBundle.getOriginalCreatedDate(),
+ baseBundle.getCreatedDate(),
+ baseBundle.getUpdatedDate());
+ bundles.add(subscriptionBundle);
}
- final List<SubscriptionBundle> result = new ArrayList<SubscriptionBundle>(perBundleEntitlements.keySet().size());
- for (UUID bundleId : perBundleEntitlements.keySet()) {
- final List<Entitlement> allEntitlementsForBundle = perBundleEntitlements.get(bundleId);
- final SubscriptionBundle bundle = getSubscriptionBundleFromEntitlements(bundleId, allEntitlementsForBundle, context);
- result.add(bundle);
- }
- return result;
+ return bundles;
}
- private Subscription fromEntitlement(final Entitlement entitlement, final InternalTenantContext internalTenantContext) {
-
- final List<BlockingState> states = blockingStateDao.getBlockingState(entitlement.getId(), BlockingStateType.SUBSCRIPTION, internalTenantContext);
- final Subscription result = new DefaultSubscription((DefaultEntitlement) entitlement, states);
- return result;
- }
-
- private SubscriptionBundle getSubscriptionBundleFromEntitlements(final UUID bundleId, final List<Entitlement> entitlements, final TenantContext context) throws SubscriptionBaseApiException, AccountApiException {
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
- final SubscriptionBaseBundle baseBundle = subscriptionInternalApi.getBundleFromId(bundleId, internalTenantContext);
- final List<Subscription> subscriptions = new ArrayList<Subscription>(entitlements.size());
- subscriptions.addAll(Collections2.transform(entitlements, new Function<Entitlement, Subscription>() {
- @Override
- public Subscription apply(final Entitlement input) {
- return fromEntitlement(input, internalTenantContext);
+ private Map<UUID, List<Subscription>> buildSubscriptionsFromEntitlements(final AccountEntitlements accountEntitlements) {
+ final Map<UUID, List<Subscription>> subscriptionsPerBundle = new HashMap<UUID, List<Subscription>>();
+ for (final UUID bundleId : accountEntitlements.getEntitlements().keySet()) {
+ if (subscriptionsPerBundle.get(bundleId) == null) {
+ subscriptionsPerBundle.put(bundleId, new LinkedList<Subscription>());
}
- }));
-
- final Account account = accountApi.getAccountById(baseBundle.getAccountId(), internalTenantContext);
-
- final InternalTenantContext internalTenantContextWithAccountRecordId = internalCallContextFactory.createInternalTenantContext(account.getId(), context);
-
- final DateTimeZone accountTimeZone = account.getTimeZone();
- final List<BlockingState> allBlockingStatesPerAccountRecordId = blockingStateDao.getBlockingAllForAccountRecordId(internalTenantContextWithAccountRecordId);
- final Set<UUID> allEntitlementIds = new HashSet<UUID>(Collections2.<Entitlement, UUID>transform(entitlements, new Function<Entitlement, UUID>() {
- @Override
- public UUID apply(final Entitlement input) {
- return input.getId();
+ for (final Entitlement entitlement : accountEntitlements.getEntitlements().get(bundleId)) {
+ if (entitlement instanceof DefaultEntitlement) {
+ subscriptionsPerBundle.get(bundleId).add(new DefaultSubscription((DefaultEntitlement) entitlement));
+ } else {
+ throw new ShouldntHappenException("Entitlement should be a DefaultEntitlement instance");
+ }
}
- }));
-
- final List<BlockingState> filteredBlockingStates = new LinkedList<BlockingState>(Collections2.filter(allBlockingStatesPerAccountRecordId, new Predicate<BlockingState>() {
- @Override
- public boolean apply(final BlockingState input) {
- return input.getType() == BlockingStateType.ACCOUNT ||
- (input.getType() == BlockingStateType.SUBSCRIPTION_BUNDLE && input.getBlockedId().equals(bundleId)) ||
- (input.getType() == BlockingStateType.SUBSCRIPTION && allEntitlementIds.contains(input.getBlockedId()));
- }
- }));
-
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, account.getId(), bundleId, baseBundle.getExternalKey(), entitlements, filteredBlockingStates);
- final DefaultSubscriptionBundle bundle = new DefaultSubscriptionBundle(bundleId, baseBundle.getAccountId(), baseBundle.getExternalKey(), subscriptions, timeline, baseBundle.getOriginalCreatedDate() , baseBundle.getCreatedDate(), baseBundle.getUpdatedDate());
- return bundle;
+ }
+ return subscriptionsPerBundle;
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
index 796eb06..608e6b6 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -56,13 +57,11 @@ import com.google.common.collect.ImmutableList;
public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTimeline {
-
private final Logger logger = LoggerFactory.getLogger(DefaultSubscriptionBundleTimeline.class);
// STEPH This is added to give us confidence the timeline we generate behaves as expected. Could be removed at some point
private final static String TIMELINE_WARN_LOG = "Sanity Timeline: ";
-
public static final String BILLING_SERVICE_NAME = "billing-service";
public static final String ENT_BILLING_SERVICE_NAME = "entitlement+billing-service";
@@ -71,6 +70,18 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
private final UUID bundleId;
private final String externalKey;
+ public DefaultSubscriptionBundleTimeline(final DateTimeZone accountTimeZone, final UUID accountId, final UUID bundleId, final String externalKey, final Collection<Entitlement> entitlements) {
+ final Collection<BlockingState> blockingStates = new HashSet<BlockingState>();
+ for (final Entitlement entitlement : entitlements) {
+ blockingStates.addAll(((DefaultEntitlement) entitlement).getEventsStream().getSubscriptionEntitlementStates());
+ blockingStates.addAll(((DefaultEntitlement) entitlement).getEventsStream().getBundleEntitlementStates());
+ blockingStates.addAll(((DefaultEntitlement) entitlement).getEventsStream().getAccountEntitlementStates());
+ }
+ this.accountId = accountId;
+ this.bundleId = bundleId;
+ this.externalKey = externalKey;
+ this.events = computeEvents(entitlements, new LinkedList<BlockingState>(blockingStates), accountTimeZone);
+ }
public DefaultSubscriptionBundleTimeline(final DateTimeZone accountTimeZone, final UUID accountId, final UUID bundleId, final String externalKey, final List<Entitlement> entitlements, List<BlockingState> allBlockingStates) {
this.accountId = accountId;
@@ -85,7 +96,7 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
// - base subscription events are already ordered for each Entitlement and so when we reorder at the bundle level we try not to break that initial ordering
// - blocking state events occur at various level (account, bundle and subscription) so for higher level, we need to dispatch that on each subscription.
//
- private List<SubscriptionEvent> computeEvents(final List<Entitlement> entitlements, List<BlockingState> allBlockingStates, final DateTimeZone accountTimeZone) {
+ private List<SubscriptionEvent> computeEvents(final Collection<Entitlement> entitlements, List<BlockingState> allBlockingStates, final DateTimeZone accountTimeZone) {
// Extract ids for all entitlement in the list
final Set<UUID> allEntitlementUUIDs = new TreeSet(Collections2.transform(entitlements, new Function<Entitlement, UUID>() {
@@ -171,7 +182,7 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
int currentIndex = i;
if (shouldSwap) {
- Collections.swap(events, i, i+1);
+ Collections.swap(events, i, i + 1);
}
if (shouldReverseSort) {
while (currentIndex >= 1) {
@@ -189,7 +200,6 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
}
}
-
private boolean shouldSwap(DefaultSubscriptionEvent cur, DefaultSubscriptionEvent other, boolean isAscending) {
// For a given date, order by subscriptionId, and within subscription by event type
@@ -198,12 +208,11 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
((isAscending &&
((idComp > 0) ||
(idComp == 0 && cur.getSubscriptionEventType().ordinal() > other.getSubscriptionEventType().ordinal()))) ||
- (!isAscending &&
- ((idComp < 0) ||
- (idComp == 0 && cur.getSubscriptionEventType().ordinal() < other.getSubscriptionEventType().ordinal())))));
+ (!isAscending &&
+ ((idComp < 0) ||
+ (idComp == 0 && cur.getSubscriptionEventType().ordinal() < other.getSubscriptionEventType().ordinal())))));
}
-
private void insertAfterIndex(final LinkedList<SubscriptionEvent> original, final List<SubscriptionEvent> newEvents, int index) {
final boolean firstPosition = (index == -1);
@@ -227,7 +236,6 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
//
private int insertFromBlockingEvent(final DateTimeZone accountTimeZone, final Set<UUID> allEntitlementUUIDs, final List<SubscriptionEvent> result, final BlockingState bs, final DateTime bsEffectiveDate, final List<SubscriptionEvent> newEvents) {
-
// Keep the current state per entitlement
final Map<UUID, TargetState> targetStates = new HashMap<UUID, TargetState>();
for (UUID cur : allEntitlementUUIDs) {
@@ -325,7 +333,7 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
}
// Compute the initial stream of events based on the subscription base events
- private LinkedList<SubscriptionEvent> computeSubscriptionBaseEvents(final List<Entitlement> entitlements, final DateTimeZone accountTimeZone) {
+ private LinkedList<SubscriptionEvent> computeSubscriptionBaseEvents(final Collection<Entitlement> entitlements, final DateTimeZone accountTimeZone) {
final LinkedList<SubscriptionEvent> result = new LinkedList<SubscriptionEvent>();
for (final Entitlement cur : entitlements) {
final SubscriptionBase base = ((DefaultEntitlement) cur).getSubscriptionBase();
@@ -404,7 +412,6 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
result.add(index, event);
}
-
private SubscriptionEvent toSubscriptionEvent(final SubscriptionEvent prev, final SubscriptionEvent next, final UUID entitlementId, final BlockingState in, final SubscriptionEventType eventType, final DateTimeZone accountTimeZone) {
return new DefaultSubscriptionEvent(in.getId(),
entitlementId,
@@ -430,7 +437,6 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
accountTimeZone);
}
-
private SubscriptionEvent toSubscriptionEvent(final SubscriptionBaseTransition in, final SubscriptionEventType eventType, final DateTimeZone accountTimeZone) {
return new DefaultSubscriptionEvent(in.getId(),
in.getSubscriptionId(),
@@ -526,415 +532,413 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
return events;
}
-//
-// Internal class to keep the state associated with each subscription
-//
-private final static class TargetState {
-
- private boolean isEntitlementStarted;
- private boolean isEntitlementStopped;
- private boolean isBillingStarted;
- private boolean isBillingStopped;
- private Map<String, BlockingState> perServiceBlockingState;
-
- public TargetState() {
- this.isEntitlementStarted = false;
- this.isEntitlementStopped = false;
- this.isBillingStarted = false;
- this.isBillingStopped = false;
- this.perServiceBlockingState = new HashMap<String, BlockingState>();
- }
+ //
+ // Internal class to keep the state associated with each subscription
+ //
+ private final static class TargetState {
- public void setEntitlementStarted() {
- isEntitlementStarted = true;
- }
+ private boolean isEntitlementStarted;
+ private boolean isEntitlementStopped;
+ private boolean isBillingStarted;
+ private boolean isBillingStopped;
+ private Map<String, BlockingState> perServiceBlockingState;
- public void setEntitlementStopped() {
- isEntitlementStopped = true;
- }
+ public TargetState() {
+ this.isEntitlementStarted = false;
+ this.isEntitlementStopped = false;
+ this.isBillingStarted = false;
+ this.isBillingStopped = false;
+ this.perServiceBlockingState = new HashMap<String, BlockingState>();
+ }
- public void setBillingStarted() {
- isBillingStarted = true;
- }
+ public void setEntitlementStarted() {
+ isEntitlementStarted = true;
+ }
- public void setBillingStopped() {
- isBillingStopped = true;
- }
+ public void setEntitlementStopped() {
+ isEntitlementStopped = true;
+ }
- public void addEntitlementEvent(final SubscriptionEvent e) {
- final BlockingState converted = new DefaultBlockingState(e.getEntitlementId(), BlockingStateType.SUBSCRIPTION,
- e.getServiceStateName(), e.getServiceName(), false, e.isBlockedEntitlement(), e.isBlockedBilling(),
- ((DefaultSubscriptionEvent) e).getEffectiveDateTime());
- perServiceBlockingState.put(converted.getService(), converted);
+ public void setBillingStarted() {
+ isBillingStarted = true;
+ }
- }
+ public void setBillingStopped() {
+ isBillingStopped = true;
+ }
+
+ public void addEntitlementEvent(final SubscriptionEvent e) {
+ final BlockingState converted = new DefaultBlockingState(e.getEntitlementId(), BlockingStateType.SUBSCRIPTION,
+ e.getServiceStateName(), e.getServiceName(), false, e.isBlockedEntitlement(), e.isBlockedBilling(),
+ ((DefaultSubscriptionEvent) e).getEffectiveDateTime());
+ perServiceBlockingState.put(converted.getService(), converted);
- //
- // From the current state of that subscription, compute the effect of the new state based on the incoming blockingState event
- //
- private List<SubscriptionEventType> addStateAndReturnEventTypes(final BlockingState bs) {
-
- // Turn off isBlockedEntitlement and isBlockedBilling if there was not start event
- final BlockingState fixedBlockingState = new DefaultBlockingState(bs.getBlockedId(),
- bs.getType(),
- bs.getStateName(),
- bs.getService(),
- bs.isBlockChange(),
- (bs.isBlockEntitlement() && isEntitlementStarted && !isEntitlementStopped),
- (bs.isBlockBilling() && isBillingStarted && !isBillingStopped),
- bs.getEffectiveDate());
-
- final List<SubscriptionEventType> result = new ArrayList<SubscriptionEventType>(4);
- if (fixedBlockingState.getStateName().equals(DefaultEntitlementApi.ENT_STATE_CANCELLED)) {
- isEntitlementStopped = true;
- result.add(SubscriptionEventType.STOP_ENTITLEMENT);
- return result;
}
//
- // We look at the effect of the incoming event for the specific service, and then recompute the state after so we can compare if anything has changed
- // across all services
+ // From the current state of that subscription, compute the effect of the new state based on the incoming blockingState event
//
- final BlockingAggregator stateBefore = getState();
- perServiceBlockingState.put(fixedBlockingState.getService(), fixedBlockingState);
- final BlockingAggregator stateAfter = getState();
+ private List<SubscriptionEventType> addStateAndReturnEventTypes(final BlockingState bs) {
+
+ // Turn off isBlockedEntitlement and isBlockedBilling if there was not start event
+ final BlockingState fixedBlockingState = new DefaultBlockingState(bs.getBlockedId(),
+ bs.getType(),
+ bs.getStateName(),
+ bs.getService(),
+ bs.isBlockChange(),
+ (bs.isBlockEntitlement() && isEntitlementStarted && !isEntitlementStopped),
+ (bs.isBlockBilling() && isBillingStarted && !isBillingStopped),
+ bs.getEffectiveDate());
+
+ final List<SubscriptionEventType> result = new ArrayList<SubscriptionEventType>(4);
+ if (fixedBlockingState.getStateName().equals(DefaultEntitlementApi.ENT_STATE_CANCELLED)) {
+ isEntitlementStopped = true;
+ result.add(SubscriptionEventType.STOP_ENTITLEMENT);
+ return result;
+ }
- final boolean shouldResumeEntitlement = isEntitlementStarted && !isEntitlementStopped && stateBefore.isBlockEntitlement() && !stateAfter.isBlockEntitlement();
- if (shouldResumeEntitlement) {
- result.add(SubscriptionEventType.RESUME_ENTITLEMENT);
- }
- final boolean shouldResumeBilling = isBillingStarted && !isBillingStopped && stateBefore.isBlockBilling() && !stateAfter.isBlockBilling();
- if (shouldResumeBilling) {
- result.add(SubscriptionEventType.RESUME_BILLING);
- }
+ //
+ // We look at the effect of the incoming event for the specific service, and then recompute the state after so we can compare if anything has changed
+ // across all services
+ //
+ final BlockingAggregator stateBefore = getState();
+ perServiceBlockingState.put(fixedBlockingState.getService(), fixedBlockingState);
+ final BlockingAggregator stateAfter = getState();
- final boolean shouldBlockEntitlement = isEntitlementStarted && !isEntitlementStopped && !stateBefore.isBlockEntitlement() && stateAfter.isBlockEntitlement();
- if (shouldBlockEntitlement) {
- result.add(SubscriptionEventType.PAUSE_ENTITLEMENT);
- }
- final boolean shouldBlockBilling = isBillingStarted && !isBillingStopped && !stateBefore.isBlockBilling() && stateAfter.isBlockBilling();
- if (shouldBlockBilling) {
- result.add(SubscriptionEventType.PAUSE_BILLING);
- }
+ final boolean shouldResumeEntitlement = isEntitlementStarted && !isEntitlementStopped && stateBefore.isBlockEntitlement() && !stateAfter.isBlockEntitlement();
+ if (shouldResumeEntitlement) {
+ result.add(SubscriptionEventType.RESUME_ENTITLEMENT);
+ }
+ final boolean shouldResumeBilling = isBillingStarted && !isBillingStopped && stateBefore.isBlockBilling() && !stateAfter.isBlockBilling();
+ if (shouldResumeBilling) {
+ result.add(SubscriptionEventType.RESUME_BILLING);
+ }
+
+ final boolean shouldBlockEntitlement = isEntitlementStarted && !isEntitlementStopped && !stateBefore.isBlockEntitlement() && stateAfter.isBlockEntitlement();
+ if (shouldBlockEntitlement) {
+ result.add(SubscriptionEventType.PAUSE_ENTITLEMENT);
+ }
+ final boolean shouldBlockBilling = isBillingStarted && !isBillingStopped && !stateBefore.isBlockBilling() && stateAfter.isBlockBilling();
+ if (shouldBlockBilling) {
+ result.add(SubscriptionEventType.PAUSE_BILLING);
+ }
- if (!shouldResumeEntitlement && !shouldBlockEntitlement && !shouldBlockEntitlement && !shouldBlockBilling && !fixedBlockingState.getService().equals(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME)) {
- result.add(SubscriptionEventType.SERVICE_STATE_CHANGE);
+ if (!shouldResumeEntitlement && !shouldBlockEntitlement && !shouldBlockEntitlement && !shouldBlockBilling && !fixedBlockingState.getService().equals(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME)) {
+ result.add(SubscriptionEventType.SERVICE_STATE_CHANGE);
+ }
+ return result;
}
- return result;
- }
- private BlockingAggregator getState() {
- final DefaultBlockingAggregator aggrBefore = new DefaultBlockingAggregator();
- for (BlockingState cur : perServiceBlockingState.values()) {
- aggrBefore.or(cur);
+ private BlockingAggregator getState() {
+ final DefaultBlockingAggregator aggrBefore = new DefaultBlockingAggregator();
+ for (BlockingState cur : perServiceBlockingState.values()) {
+ aggrBefore.or(cur);
+ }
+ return aggrBefore;
+ }
+ }
+
+ protected static final class DefaultSubscriptionEvent implements SubscriptionEvent {
+
+ private final UUID id;
+ private final UUID entitlementId;
+ private final DateTime effectiveDate;
+ private final DateTime requestedDate;
+ private final SubscriptionEventType eventType;
+ private final boolean isBlockingEntitlement;
+ private final boolean isBlockingBilling;
+ private final String serviceName;
+ private final String serviceStateName;
+ private final Product prevProduct;
+ private final Plan prevPlan;
+ private final PlanPhase prevPlanPhase;
+ private final PriceList prevPriceList;
+ private final BillingPeriod prevBillingPeriod;
+ private final Product nextProduct;
+ private final Plan nextPlan;
+ private final PlanPhase nextPlanPhase;
+ private final PriceList nextPriceList;
+ private final BillingPeriod nextBillingPeriod;
+ private final DateTime createdDate;
+ private final DateTimeZone accountTimeZone;
+
+ public DefaultSubscriptionEvent(final UUID id,
+ final UUID entitlementId,
+ final DateTime effectiveDate,
+ final DateTime requestedDate,
+ final SubscriptionEventType eventType,
+ final boolean blockingEntitlement,
+ final boolean blockingBilling,
+ final String serviceName,
+ final String serviceStateName,
+ final Product prevProduct,
+ final Plan prevPlan,
+ final PlanPhase prevPlanPhase,
+ final PriceList prevPriceList,
+ final BillingPeriod prevBillingPeriod,
+ final Product nextProduct,
+ final Plan nextPlan,
+ final PlanPhase nextPlanPhase,
+ final PriceList nextPriceList,
+ final BillingPeriod nextBillingPeriod,
+ final DateTime createDate,
+ final DateTimeZone accountTimeZone) {
+ this.id = id;
+ this.entitlementId = entitlementId;
+ this.effectiveDate = effectiveDate;
+ this.requestedDate = requestedDate;
+ this.eventType = eventType;
+ this.isBlockingEntitlement = blockingEntitlement;
+ this.isBlockingBilling = blockingBilling;
+ this.serviceName = serviceName;
+ this.serviceStateName = serviceStateName;
+ this.prevProduct = prevProduct;
+ this.prevPlan = prevPlan;
+ this.prevPlanPhase = prevPlanPhase;
+ this.prevPriceList = prevPriceList;
+ this.prevBillingPeriod = prevBillingPeriod;
+ this.nextProduct = nextProduct;
+ this.nextPlan = nextPlan;
+ this.nextPlanPhase = nextPlanPhase;
+ this.nextPriceList = nextPriceList;
+ this.nextBillingPeriod = nextBillingPeriod;
+ this.createdDate = createDate;
+ this.accountTimeZone = accountTimeZone;
+ }
+
+ private DefaultSubscriptionEvent(DefaultSubscriptionEvent copy, SubscriptionEventType newEventType) {
+ this(copy.getId(),
+ copy.getEntitlementId(),
+ copy.getEffectiveDateTime(),
+ copy.getRequestedDateTime(),
+ newEventType,
+ copy.isBlockedEntitlement(),
+ copy.isBlockedBilling(),
+ copy.getServiceName(),
+ copy.getServiceStateName(),
+ copy.getPrevProduct(),
+ copy.getPrevPlan(),
+ copy.getPrevPhase(),
+ copy.getPrevPriceList(),
+ copy.getPrevBillingPeriod(),
+ copy.getNextProduct(),
+ copy.getNextPlan(),
+ copy.getNextPhase(),
+ copy.getNextPriceList(),
+ copy.getNextBillingPeriod(),
+ copy.getCreatedDate(),
+ copy.getAccountTimeZone());
}
- return aggrBefore;
- }
-}
+ public DateTimeZone getAccountTimeZone() {
+ return accountTimeZone;
+ }
-protected static final class DefaultSubscriptionEvent implements SubscriptionEvent {
-
- private final UUID id;
- private final UUID entitlementId;
- private final DateTime effectiveDate;
- private final DateTime requestedDate;
- private final SubscriptionEventType eventType;
- private final boolean isBlockingEntitlement;
- private final boolean isBlockingBilling;
- private final String serviceName;
- private final String serviceStateName;
- private final Product prevProduct;
- private final Plan prevPlan;
- private final PlanPhase prevPlanPhase;
- private final PriceList prevPriceList;
- private final BillingPeriod prevBillingPeriod;
- private final Product nextProduct;
- private final Plan nextPlan;
- private final PlanPhase nextPlanPhase;
- private final PriceList nextPriceList;
- private final BillingPeriod nextBillingPeriod;
- private final DateTime createdDate;
- private final DateTimeZone accountTimeZone;
-
-
- public DefaultSubscriptionEvent(final UUID id,
- final UUID entitlementId,
- final DateTime effectiveDate,
- final DateTime requestedDate,
- final SubscriptionEventType eventType,
- final boolean blockingEntitlement,
- final boolean blockingBilling,
- final String serviceName,
- final String serviceStateName,
- final Product prevProduct,
- final Plan prevPlan,
- final PlanPhase prevPlanPhase,
- final PriceList prevPriceList,
- final BillingPeriod prevBillingPeriod,
- final Product nextProduct,
- final Plan nextPlan,
- final PlanPhase nextPlanPhase,
- final PriceList nextPriceList,
- final BillingPeriod nextBillingPeriod,
- final DateTime createDate,
- final DateTimeZone accountTimeZone) {
- this.id = id;
- this.entitlementId = entitlementId;
- this.effectiveDate = effectiveDate;
- this.requestedDate = requestedDate;
- this.eventType = eventType;
- this.isBlockingEntitlement = blockingEntitlement;
- this.isBlockingBilling = blockingBilling;
- this.serviceName = serviceName;
- this.serviceStateName = serviceStateName;
- this.prevProduct = prevProduct;
- this.prevPlan = prevPlan;
- this.prevPlanPhase = prevPlanPhase;
- this.prevPriceList = prevPriceList;
- this.prevBillingPeriod = prevBillingPeriod;
- this.nextProduct = nextProduct;
- this.nextPlan = nextPlan;
- this.nextPlanPhase = nextPlanPhase;
- this.nextPriceList = nextPriceList;
- this.nextBillingPeriod = nextBillingPeriod;
- this.createdDate = createDate;
- this.accountTimeZone = accountTimeZone;
- }
+ public DateTime getEffectiveDateTime() {
+ return effectiveDate;
+ }
- private DefaultSubscriptionEvent(DefaultSubscriptionEvent copy, SubscriptionEventType newEventType) {
- this(copy.getId(),
- copy.getEntitlementId(),
- copy.getEffectiveDateTime(),
- copy.getRequestedDateTime(),
- newEventType,
- copy.isBlockedEntitlement(),
- copy.isBlockedBilling(),
- copy.getServiceName(),
- copy.getServiceStateName(),
- copy.getPrevProduct(),
- copy.getPrevPlan(),
- copy.getPrevPhase(),
- copy.getPrevPriceList(),
- copy.getPrevBillingPeriod(),
- copy.getNextProduct(),
- copy.getNextPlan(),
- copy.getNextPhase(),
- copy.getNextPriceList(),
- copy.getNextBillingPeriod(),
- copy.getCreatedDate(),
- copy.getAccountTimeZone());
- }
+ public DateTime getRequestedDateTime() {
+ return requestedDate;
+ }
- public DateTimeZone getAccountTimeZone() {
- return accountTimeZone;
- }
+ @Override
+ public UUID getId() {
+ return id;
+ }
- public DateTime getEffectiveDateTime() {
- return effectiveDate;
- }
+ @Override
+ public UUID getEntitlementId() {
+ return entitlementId;
+ }
- public DateTime getRequestedDateTime() {
- return requestedDate;
- }
+ @Override
+ public LocalDate getEffectiveDate() {
+ return effectiveDate != null ? new LocalDate(effectiveDate, accountTimeZone) : null;
+ }
- @Override
- public UUID getId() {
- return id;
- }
+ @Override
+ public LocalDate getRequestedDate() {
+ return requestedDate != null ? new LocalDate(requestedDate, accountTimeZone) : null;
+ }
- @Override
- public UUID getEntitlementId() {
- return entitlementId;
- }
+ @Override
+ public SubscriptionEventType getSubscriptionEventType() {
+ return eventType;
+ }
- @Override
- public LocalDate getEffectiveDate() {
- return effectiveDate != null ? new LocalDate(effectiveDate, accountTimeZone) : null;
- }
+ @Override
+ public boolean isBlockedBilling() {
+ return isBlockingBilling;
+ }
- @Override
- public LocalDate getRequestedDate() {
- return requestedDate != null ? new LocalDate(requestedDate, accountTimeZone) : null;
- }
+ @Override
+ public boolean isBlockedEntitlement() {
+ return isBlockingEntitlement;
+ }
- @Override
- public SubscriptionEventType getSubscriptionEventType() {
- return eventType;
- }
+ @Override
+ public String getServiceName() {
+ return serviceName;
+ }
- @Override
- public boolean isBlockedBilling() {
- return isBlockingBilling;
- }
+ @Override
+ public String getServiceStateName() {
+ return serviceStateName;
+ }
- @Override
- public boolean isBlockedEntitlement() {
- return isBlockingEntitlement;
- }
+ @Override
+ public Product getPrevProduct() {
+ return prevProduct;
+ }
- @Override
- public String getServiceName() {
- return serviceName;
- }
+ @Override
+ public Plan getPrevPlan() {
+ return prevPlan;
+ }
- @Override
- public String getServiceStateName() {
- return serviceStateName;
- }
+ @Override
+ public PlanPhase getPrevPhase() {
+ return prevPlanPhase;
+ }
- @Override
- public Product getPrevProduct() {
- return prevProduct;
- }
+ @Override
+ public PriceList getPrevPriceList() {
+ return prevPriceList;
+ }
- @Override
- public Plan getPrevPlan() {
- return prevPlan;
- }
+ @Override
+ public BillingPeriod getPrevBillingPeriod() {
+ return prevBillingPeriod;
+ }
- @Override
- public PlanPhase getPrevPhase() {
- return prevPlanPhase;
- }
+ @Override
+ public Product getNextProduct() {
+ return nextProduct;
+ }
- @Override
- public PriceList getPrevPriceList() {
- return prevPriceList;
- }
+ @Override
+ public Plan getNextPlan() {
+ return nextPlan;
+ }
- @Override
- public BillingPeriod getPrevBillingPeriod() {
- return prevBillingPeriod;
- }
+ @Override
+ public PlanPhase getNextPhase() {
+ return nextPlanPhase;
+ }
- @Override
- public Product getNextProduct() {
- return nextProduct;
- }
+ @Override
+ public PriceList getNextPriceList() {
+ return nextPriceList;
+ }
- @Override
- public Plan getNextPlan() {
- return nextPlan;
- }
+ @Override
+ public BillingPeriod getNextBillingPeriod() {
+ return nextBillingPeriod;
+ }
- @Override
- public PlanPhase getNextPhase() {
- return nextPlanPhase;
- }
+ public DateTime getCreatedDate() {
+ return createdDate;
+ }
- @Override
- public PriceList getNextPriceList() {
- return nextPriceList;
- }
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
- @Override
- public BillingPeriod getNextBillingPeriod() {
- return nextBillingPeriod;
- }
+ final DefaultSubscriptionEvent that = (DefaultSubscriptionEvent) o;
- public DateTime getCreatedDate() {
- return createdDate;
- }
+ if (isBlockingBilling != that.isBlockingBilling) {
+ return false;
+ }
+ if (isBlockingEntitlement != that.isBlockingEntitlement) {
+ return false;
+ }
+ if (createdDate != null ? !createdDate.equals(that.createdDate) : that.createdDate != null) {
+ return false;
+ }
+ if (effectiveDate != null ? !effectiveDate.equals(that.effectiveDate) : that.effectiveDate != null) {
+ return false;
+ }
+ if (entitlementId != null ? !entitlementId.equals(that.entitlementId) : that.entitlementId != null) {
+ return false;
+ }
+ if (eventType != that.eventType) {
+ return false;
+ }
+ if (id != null ? !id.equals(that.id) : that.id != null) {
+ return false;
+ }
+ if (nextBillingPeriod != that.nextBillingPeriod) {
+ return false;
+ }
+ if (nextPlan != null ? !nextPlan.equals(that.nextPlan) : that.nextPlan != null) {
+ return false;
+ }
+ if (nextPlanPhase != null ? !nextPlanPhase.equals(that.nextPlanPhase) : that.nextPlanPhase != null) {
+ return false;
+ }
+ if (nextPriceList != null ? !nextPriceList.equals(that.nextPriceList) : that.nextPriceList != null) {
+ return false;
+ }
+ if (nextProduct != null ? !nextProduct.equals(that.nextProduct) : that.nextProduct != null) {
+ return false;
+ }
+ if (prevBillingPeriod != that.prevBillingPeriod) {
+ return false;
+ }
+ if (prevPlan != null ? !prevPlan.equals(that.prevPlan) : that.prevPlan != null) {
+ return false;
+ }
+ if (prevPlanPhase != null ? !prevPlanPhase.equals(that.prevPlanPhase) : that.prevPlanPhase != null) {
+ return false;
+ }
+ if (prevPriceList != null ? !prevPriceList.equals(that.prevPriceList) : that.prevPriceList != null) {
+ return false;
+ }
+ if (prevProduct != null ? !prevProduct.equals(that.prevProduct) : that.prevProduct != null) {
+ return false;
+ }
+ if (requestedDate != null ? !requestedDate.equals(that.requestedDate) : that.requestedDate != null) {
+ return false;
+ }
+ if (serviceName != null ? !serviceName.equals(that.serviceName) : that.serviceName != null) {
+ return false;
+ }
+ if (serviceStateName != null ? !serviceStateName.equals(that.serviceStateName) : that.serviceStateName != null) {
+ return false;
+ }
- @Override
- public boolean equals(final Object o) {
- if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- final DefaultSubscriptionEvent that = (DefaultSubscriptionEvent) o;
- if (isBlockingBilling != that.isBlockingBilling) {
- return false;
- }
- if (isBlockingEntitlement != that.isBlockingEntitlement) {
- return false;
- }
- if (createdDate != null ? !createdDate.equals(that.createdDate) : that.createdDate != null) {
- return false;
- }
- if (effectiveDate != null ? !effectiveDate.equals(that.effectiveDate) : that.effectiveDate != null) {
- return false;
- }
- if (entitlementId != null ? !entitlementId.equals(that.entitlementId) : that.entitlementId != null) {
- return false;
- }
- if (eventType != that.eventType) {
- return false;
- }
- if (id != null ? !id.equals(that.id) : that.id != null) {
- return false;
- }
- if (nextBillingPeriod != that.nextBillingPeriod) {
- return false;
- }
- if (nextPlan != null ? !nextPlan.equals(that.nextPlan) : that.nextPlan != null) {
- return false;
- }
- if (nextPlanPhase != null ? !nextPlanPhase.equals(that.nextPlanPhase) : that.nextPlanPhase != null) {
- return false;
- }
- if (nextPriceList != null ? !nextPriceList.equals(that.nextPriceList) : that.nextPriceList != null) {
- return false;
- }
- if (nextProduct != null ? !nextProduct.equals(that.nextProduct) : that.nextProduct != null) {
- return false;
- }
- if (prevBillingPeriod != that.prevBillingPeriod) {
- return false;
- }
- if (prevPlan != null ? !prevPlan.equals(that.prevPlan) : that.prevPlan != null) {
- return false;
- }
- if (prevPlanPhase != null ? !prevPlanPhase.equals(that.prevPlanPhase) : that.prevPlanPhase != null) {
- return false;
- }
- if (prevPriceList != null ? !prevPriceList.equals(that.prevPriceList) : that.prevPriceList != null) {
- return false;
- }
- if (prevProduct != null ? !prevProduct.equals(that.prevProduct) : that.prevProduct != null) {
- return false;
- }
- if (requestedDate != null ? !requestedDate.equals(that.requestedDate) : that.requestedDate != null) {
- return false;
- }
- if (serviceName != null ? !serviceName.equals(that.serviceName) : that.serviceName != null) {
- return false;
- }
- if (serviceStateName != null ? !serviceStateName.equals(that.serviceStateName) : that.serviceStateName != null) {
- return false;
+ @Override
+ public int hashCode() {
+ int result = id != null ? id.hashCode() : 0;
+ result = 31 * result + (entitlementId != null ? entitlementId.hashCode() : 0);
+ result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0);
+ result = 31 * result + (requestedDate != null ? requestedDate.hashCode() : 0);
+ result = 31 * result + (eventType != null ? eventType.hashCode() : 0);
+ result = 31 * result + (isBlockingEntitlement ? 1 : 0);
+ result = 31 * result + (isBlockingBilling ? 1 : 0);
+ result = 31 * result + (serviceName != null ? serviceName.hashCode() : 0);
+ result = 31 * result + (serviceStateName != null ? serviceStateName.hashCode() : 0);
+ result = 31 * result + (prevProduct != null ? prevProduct.hashCode() : 0);
+ result = 31 * result + (prevPlan != null ? prevPlan.hashCode() : 0);
+ result = 31 * result + (prevPlanPhase != null ? prevPlanPhase.hashCode() : 0);
+ result = 31 * result + (prevPriceList != null ? prevPriceList.hashCode() : 0);
+ result = 31 * result + (prevBillingPeriod != null ? prevBillingPeriod.hashCode() : 0);
+ result = 31 * result + (nextProduct != null ? nextProduct.hashCode() : 0);
+ result = 31 * result + (nextPlan != null ? nextPlan.hashCode() : 0);
+ result = 31 * result + (nextPlanPhase != null ? nextPlanPhase.hashCode() : 0);
+ result = 31 * result + (nextPriceList != null ? nextPriceList.hashCode() : 0);
+ result = 31 * result + (nextBillingPeriod != null ? nextBillingPeriod.hashCode() : 0);
+ result = 31 * result + (createdDate != null ? createdDate.hashCode() : 0);
+ return result;
}
-
- return true;
}
-
- @Override
- public int hashCode() {
- int result = id != null ? id.hashCode() : 0;
- result = 31 * result + (entitlementId != null ? entitlementId.hashCode() : 0);
- result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0);
- result = 31 * result + (requestedDate != null ? requestedDate.hashCode() : 0);
- result = 31 * result + (eventType != null ? eventType.hashCode() : 0);
- result = 31 * result + (isBlockingEntitlement ? 1 : 0);
- result = 31 * result + (isBlockingBilling ? 1 : 0);
- result = 31 * result + (serviceName != null ? serviceName.hashCode() : 0);
- result = 31 * result + (serviceStateName != null ? serviceStateName.hashCode() : 0);
- result = 31 * result + (prevProduct != null ? prevProduct.hashCode() : 0);
- result = 31 * result + (prevPlan != null ? prevPlan.hashCode() : 0);
- result = 31 * result + (prevPlanPhase != null ? prevPlanPhase.hashCode() : 0);
- result = 31 * result + (prevPriceList != null ? prevPriceList.hashCode() : 0);
- result = 31 * result + (prevBillingPeriod != null ? prevBillingPeriod.hashCode() : 0);
- result = 31 * result + (nextProduct != null ? nextProduct.hashCode() : 0);
- result = 31 * result + (nextPlan != null ? nextPlan.hashCode() : 0);
- result = 31 * result + (nextPlanPhase != null ? nextPlanPhase.hashCode() : 0);
- result = 31 * result + (nextPriceList != null ? nextPriceList.hashCode() : 0);
- result = 31 * result + (nextBillingPeriod != null ? nextBillingPeriod.hashCode() : 0);
- result = 31 * result + (createdDate != null ? createdDate.hashCode() : 0);
- return result;
- }
-}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultAccountEntitlements.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultAccountEntitlements.java
new file mode 100644
index 0000000..72898be
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultAccountEntitlements.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement.api.svcs;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.UUID;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.entitlement.AccountEntitlements;
+import com.ning.billing.entitlement.AccountEventsStreams;
+import com.ning.billing.entitlement.api.Entitlement;
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+
+public class DefaultAccountEntitlements implements AccountEntitlements {
+
+ private final AccountEventsStreams accountEventsStreams;
+ private final Map<UUID, Collection<Entitlement>> entitlements;
+
+ public DefaultAccountEntitlements(final AccountEventsStreams accountEventsStreams, final Map<UUID, Collection<Entitlement>> entitlements) {
+ this.accountEventsStreams = accountEventsStreams;
+ this.entitlements = entitlements;
+ }
+
+ @Override
+ public Account getAccount() {
+ return accountEventsStreams.getAccount();
+ }
+
+ @Override
+ public Map<UUID, SubscriptionBaseBundle> getBundles() {
+ return accountEventsStreams.getBundles();
+ }
+
+ @Override
+ public Map<UUID, Collection<Entitlement>> getEntitlements() {
+ return entitlements;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("DefaultAccountEntitlements{");
+ sb.append("accountEventsStreams=").append(accountEventsStreams);
+ sb.append(", entitlements=").append(entitlements);
+ 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 DefaultAccountEntitlements that = (DefaultAccountEntitlements) o;
+
+ if (accountEventsStreams != null ? !accountEventsStreams.equals(that.accountEventsStreams) : that.accountEventsStreams != null) {
+ return false;
+ }
+ if (entitlements != null ? !entitlements.equals(that.entitlements) : that.entitlements != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = accountEventsStreams != null ? accountEventsStreams.hashCode() : 0;
+ result = 31 * result + (entitlements != null ? entitlements.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultAccountEventsStreams.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultAccountEventsStreams.java
new file mode 100644
index 0000000..d05df80
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultAccountEventsStreams.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement.api.svcs;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.entitlement.AccountEventsStreams;
+import com.ning.billing.entitlement.EventsStream;
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class DefaultAccountEventsStreams implements AccountEventsStreams {
+
+ private final Account account;
+ private final Map<UUID, Collection<EventsStream>> eventsStreams;
+ private final Map<UUID, SubscriptionBaseBundle> bundles = new HashMap<UUID, SubscriptionBaseBundle>();
+
+ public DefaultAccountEventsStreams(final Account account,
+ final Iterable<SubscriptionBaseBundle> bundles,
+ final Map<UUID, Collection<EventsStream>> eventsStreams) {
+ this.account = account;
+ this.eventsStreams = eventsStreams;
+ for (final SubscriptionBaseBundle baseBundle : bundles) {
+ this.bundles.put(baseBundle.getId(), baseBundle);
+ }
+ }
+
+ public DefaultAccountEventsStreams(final Account account) {
+ this(account, ImmutableList.<SubscriptionBaseBundle>of(), ImmutableMap.<UUID, Collection<EventsStream>>of());
+ }
+
+ @Override
+ public Account getAccount() {
+ return account;
+ }
+
+ @Override
+ public Map<UUID, SubscriptionBaseBundle> getBundles() {
+ return bundles;
+ }
+
+ @Override
+ public Map<UUID, Collection<EventsStream>> getEventsStreams() {
+ return eventsStreams;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("DefaultAccountEventsStreams{");
+ sb.append("account=").append(account);
+ sb.append(", eventsStreams=").append(eventsStreams);
+ sb.append(", bundles=").append(bundles);
+ 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 DefaultAccountEventsStreams that = (DefaultAccountEventsStreams) o;
+
+ if (account != null ? !account.equals(that.account) : that.account != null) {
+ return false;
+ }
+ if (bundles != null ? !bundles.equals(that.bundles) : that.bundles != null) {
+ return false;
+ }
+ if (eventsStreams != null ? !eventsStreams.equals(that.eventsStreams) : that.eventsStreams != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = account != null ? account.hashCode() : 0;
+ result = 31 * result + (eventsStreams != null ? eventsStreams.hashCode() : 0);
+ result = 31 * result + (bundles != null ? bundles.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
new file mode 100644
index 0000000..f941e9b
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement.api.svcs;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import com.ning.billing.account.api.AccountInternalApi;
+import com.ning.billing.callcontext.InternalTenantContext;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.AccountEntitlements;
+import com.ning.billing.entitlement.AccountEventsStreams;
+import com.ning.billing.entitlement.EntitlementInternalApi;
+import com.ning.billing.entitlement.EventsStream;
+import com.ning.billing.entitlement.api.DefaultEntitlement;
+import com.ning.billing.entitlement.api.Entitlement;
+import com.ning.billing.entitlement.api.EntitlementApi;
+import com.ning.billing.entitlement.api.EntitlementApiException;
+import com.ning.billing.entitlement.api.EntitlementDateHelper;
+import com.ning.billing.entitlement.block.BlockingChecker;
+import com.ning.billing.entitlement.dao.BlockingStateDao;
+import com.ning.billing.entitlement.engine.core.EntitlementUtils;
+import com.ning.billing.entitlement.engine.core.EventsStreamBuilder;
+import com.ning.billing.notificationq.api.NotificationQueueService;
+import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
+import com.ning.billing.util.callcontext.TenantContext;
+
+public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
+
+ private final EntitlementApi entitlementApi;
+ private final SubscriptionBaseInternalApi subscriptionInternalApi;
+ private final Clock clock;
+ private final InternalCallContextFactory internalCallContextFactory;
+ private final BlockingChecker checker;
+ private final BlockingStateDao blockingStateDao;
+ private final EntitlementDateHelper dateHelper;
+ private final EventsStreamBuilder eventsStreamBuilder;
+ private final EntitlementUtils entitlementUtils;
+ private final NotificationQueueService notificationQueueService;
+
+ @Inject
+ public DefaultEntitlementInternalApi(final EntitlementApi entitlementApi, final InternalCallContextFactory internalCallContextFactory,
+ final SubscriptionBaseInternalApi subscriptionInternalApi,
+ final AccountInternalApi accountApi, final BlockingStateDao blockingStateDao, final Clock clock,
+ final BlockingChecker checker, final NotificationQueueService notificationQueueService,
+ final EventsStreamBuilder eventsStreamBuilder, final EntitlementUtils entitlementUtils) {
+ this.entitlementApi = entitlementApi;
+ this.internalCallContextFactory = internalCallContextFactory;
+ this.subscriptionInternalApi = subscriptionInternalApi;
+ this.clock = clock;
+ this.checker = checker;
+ this.blockingStateDao = blockingStateDao;
+ this.notificationQueueService = notificationQueueService;
+ this.eventsStreamBuilder = eventsStreamBuilder;
+ this.entitlementUtils = entitlementUtils;
+ this.dateHelper = new EntitlementDateHelper(accountApi, clock);
+ }
+
+ @Override
+ public AccountEntitlements getAllEntitlementsForAccountId(final UUID accountId, final TenantContext tenantContext) throws EntitlementApiException {
+ final InternalTenantContext context = internalCallContextFactory.createInternalTenantContext(accountId, tenantContext);
+
+ final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(context);
+
+ final Map<UUID, Collection<Entitlement>> entitlementsPerBundle = new HashMap<UUID, Collection<Entitlement>>();
+ for (final UUID bundleId : accountEventsStreams.getEventsStreams().keySet()) {
+ if (entitlementsPerBundle.get(bundleId) == null) {
+ entitlementsPerBundle.put(bundleId, new LinkedList<Entitlement>());
+ }
+
+ for (final EventsStream eventsStream : accountEventsStreams.getEventsStreams().get(bundleId)) {
+ final Entitlement entitlement = new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi,
+ blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
+ entitlementUtils, dateHelper, clock, internalCallContextFactory);
+ entitlementsPerBundle.get(bundleId).add(entitlement);
+ }
+ }
+
+ return new DefaultAccountEntitlements(accountEventsStreams, entitlementsPerBundle);
+ }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/block/BlockingChecker.java b/entitlement/src/main/java/com/ning/billing/entitlement/block/BlockingChecker.java
index c466378..e91dc45 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/block/BlockingChecker.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/block/BlockingChecker.java
@@ -16,11 +16,13 @@
package com.ning.billing.entitlement.block;
+import java.util.List;
import java.util.UUID;
import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.entitlement.api.Blockable;
import com.ning.billing.entitlement.api.BlockingApiException;
+import com.ning.billing.entitlement.api.BlockingState;
import com.ning.billing.entitlement.api.BlockingStateType;
public interface BlockingChecker {
@@ -33,15 +35,17 @@ public interface BlockingChecker {
public static final Object ACTION_ENTITLEMENT = "Entitlement";
public static final Object ACTION_BILLING = "Billing";
-
public interface BlockingAggregator {
+
public boolean isBlockChange();
+
public boolean isBlockEntitlement();
+
public boolean isBlockBilling();
}
- // Only throws if we can't find the blockable enties
- public BlockingAggregator getBlockedStatus(Blockable blockable, InternalTenantContext context) throws BlockingApiException;
+ public BlockingAggregator getBlockedStatus(List<BlockingState> currentAccountEntitlementStatePerService, List<BlockingState> currentBundleEntitlementStatePerService,
+ List<BlockingState> currentSubscriptionEntitlementStatePerService, InternalTenantContext internalTenantContext);
public BlockingAggregator getBlockedStatus(final UUID blockableId, final BlockingStateType type, final InternalTenantContext context) throws BlockingApiException;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java b/entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java
index 0cfe5ea..9d87e3c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java
@@ -19,6 +19,8 @@ package com.ning.billing.entitlement.block;
import java.util.List;
import java.util.UUID;
+import javax.annotation.Nullable;
+
import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
import com.ning.billing.callcontext.InternalTenantContext;
@@ -32,6 +34,7 @@ import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
public class DefaultBlockingChecker implements BlockingChecker {
@@ -110,7 +113,6 @@ public class DefaultBlockingChecker implements BlockingChecker {
return result;
}
-
private DefaultBlockingAggregator getBlockedStateBundleId(final UUID bundleId, final InternalTenantContext context) throws BlockingApiException {
final SubscriptionBaseBundle bundle;
@@ -122,7 +124,6 @@ public class DefaultBlockingChecker implements BlockingChecker {
}
}
-
private DefaultBlockingAggregator getBlockedStateBundle(final SubscriptionBaseBundle bundle, final InternalTenantContext context) {
final DefaultBlockingAggregator result = getBlockedStateAccountId(bundle.getAccountId(), context);
final DefaultBlockingAggregator bundleState = getBlockedStateForId(bundle.getId(), BlockingStateType.SUBSCRIPTION_BUNDLE, context);
@@ -143,14 +144,21 @@ public class DefaultBlockingChecker implements BlockingChecker {
return getBlockedStateForId(accountId, BlockingStateType.ACCOUNT, context);
}
- private DefaultBlockingAggregator getBlockedStateForId(final UUID blockableId, final BlockingStateType blockingStateType, final InternalTenantContext context) {
- final DefaultBlockingAggregator result = new DefaultBlockingAggregator();
+ private DefaultBlockingAggregator getBlockedStateForId(@Nullable final UUID blockableId, final BlockingStateType blockingStateType, final InternalTenantContext context) {
+ // Last states across services
+ final List<BlockingState> blockableState;
if (blockableId != null) {
- // Last states across services
- final List<BlockingState> blockableState = dao.getBlockingState(blockableId, blockingStateType, context);
- for (BlockingState cur : blockableState) {
- result.or(cur);
- }
+ blockableState = dao.getBlockingState(blockableId, blockingStateType, context);
+ } else {
+ blockableState = ImmutableList.<BlockingState>of();
+ }
+ return getBlockedState(blockableState);
+ }
+
+ private DefaultBlockingAggregator getBlockedState(final Iterable<BlockingState> currentBlockableStatePerService) {
+ final DefaultBlockingAggregator result = new DefaultBlockingAggregator();
+ for (final BlockingState cur : currentBlockableStatePerService) {
+ result.or(cur);
}
return result;
}
@@ -167,14 +175,11 @@ public class DefaultBlockingChecker implements BlockingChecker {
}
@Override
- public BlockingAggregator getBlockedStatus(final Blockable blockable, final InternalTenantContext context) throws BlockingApiException {
- if (blockable instanceof SubscriptionBase) {
- return getBlockedStateSubscription((SubscriptionBase) blockable, context);
- } else if (blockable instanceof SubscriptionBaseBundle) {
- return getBlockedStateBundle((SubscriptionBaseBundle) blockable, context);
- } else { //(blockable instanceof Account) {
- return getBlockedStateAccount((Account) blockable, context);
- }
+ public BlockingAggregator getBlockedStatus(final List<BlockingState> accountEntitlementStates, final List<BlockingState> bundleEntitlementStates, final List<BlockingState> subscriptionEntitlementStates, final InternalTenantContext internalTenantContext) {
+ final DefaultBlockingAggregator result = getBlockedState(subscriptionEntitlementStates);
+ result.or(getBlockedState(bundleEntitlementStates));
+ result.or(getBlockedState(accountEntitlementStates));
+ return result;
}
@Override
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
new file mode 100644
index 0000000..604b488
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement.dao;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.callcontext.InternalTenantContext;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.EventsStream;
+import com.ning.billing.entitlement.api.BlockingState;
+import com.ning.billing.entitlement.api.BlockingStateType;
+import com.ning.billing.entitlement.api.EntitlementApiException;
+import com.ning.billing.entitlement.engine.core.EventsStreamBuilder;
+import com.ning.billing.subscription.api.SubscriptionBase;
+import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.dao.NonEntityDao;
+
+import com.google.common.collect.ImmutableList;
+
+public class OptimizedProxyBlockingStateDao extends ProxyBlockingStateDao {
+
+ public OptimizedProxyBlockingStateDao(final EventsStreamBuilder eventsStreamBuilder, final SubscriptionBaseInternalApi subscriptionBaseInternalApi,
+ final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao) {
+ super(eventsStreamBuilder, subscriptionBaseInternalApi, dbi, clock, cacheControllerDispatcher, nonEntityDao);
+ }
+
+ // Special signature for EventsStreamBuilder to save some DAO calls
+ public List<BlockingState> getBlockingHistoryForService(final List<BlockingState> blockingStatesOnDisk,
+ final SubscriptionBaseBundle bundle,
+ @Nullable final SubscriptionBase baseSubscription,
+ final SubscriptionBase subscription,
+ final List<SubscriptionBase> allSubscriptionsForBundle,
+ final InternalTenantContext context) throws EntitlementApiException {
+ // blockable id points to a subscription, but make sure it's an add-on
+ if (!ProductCategory.ADD_ON.equals(subscription.getCategory())) {
+ // blockable id points to a base or standalone subscription, there is nothing to do
+ return blockingStatesOnDisk;
+ }
+
+ // Find all base entitlements that we care about (for which we want to find future cancelled add-ons)
+ final Iterable<EventsStream> eventsStreams = ImmutableList.<EventsStream>of(eventsStreamBuilder.buildForEntitlement(bundle,
+ baseSubscription,
+ allSubscriptionsForBundle,
+ context));
+
+ return addBlockingStatesNotOnDisk(subscription.getId(),
+ BlockingStateType.SUBSCRIPTION,
+ new LinkedList<BlockingState>(blockingStatesOnDisk),
+ ImmutableList.<SubscriptionBase>of(baseSubscription),
+ eventsStreams);
+ }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/dao/ProxyBlockingStateDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/dao/ProxyBlockingStateDao.java
index 8c96ed6..7662f22 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/dao/ProxyBlockingStateDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/dao/ProxyBlockingStateDao.java
@@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
@@ -36,12 +37,12 @@ import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.clock.Clock;
import com.ning.billing.entitlement.EntitlementService;
+import com.ning.billing.entitlement.EventsStream;
import com.ning.billing.entitlement.api.BlockingState;
import com.ning.billing.entitlement.api.BlockingStateType;
import com.ning.billing.entitlement.api.DefaultEntitlementApi;
import com.ning.billing.entitlement.api.Entitlement.EntitlementState;
import com.ning.billing.entitlement.api.EntitlementApiException;
-import com.ning.billing.entitlement.engine.core.EventsStream;
import com.ning.billing.entitlement.engine.core.EventsStreamBuilder;
import com.ning.billing.subscription.api.SubscriptionBase;
import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
@@ -61,7 +62,7 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
private static final Logger log = LoggerFactory.getLogger(ProxyBlockingStateDao.class);
// Ordering is critical here, especially for Junction
- private static final Ordering<BlockingState> BLOCKING_STATE_ORDERING = Ordering.<BlockingState>from(new Comparator<BlockingState>() {
+ public static final Ordering<BlockingState> BLOCKING_STATE_ORDERING = Ordering.<BlockingState>from(new Comparator<BlockingState>() {
@Override
public int compare(final BlockingState o1, final BlockingState o2) {
// effective_date column NOT NULL
@@ -96,10 +97,11 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
}
});
- private final EventsStreamBuilder eventsStreamBuilder;
private final SubscriptionBaseInternalApi subscriptionInternalApi;
private final Clock clock;
- private final DefaultBlockingStateDao delegate;
+
+ protected final EventsStreamBuilder eventsStreamBuilder;
+ protected final DefaultBlockingStateDao delegate;
@Inject
public ProxyBlockingStateDao(final EventsStreamBuilder eventsStreamBuilder, final SubscriptionBaseInternalApi subscriptionBaseInternalApi,
@@ -199,11 +201,12 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
// Find all base entitlements that we care about (for which we want to find future cancelled add-ons)
final Iterable<SubscriptionBase> baseSubscriptionsToConsider;
+ final Iterable<EventsStream> eventsStreams;
try {
if (blockingStateType == null) {
// We're coming from getBlockingAllForAccountRecordId
- final Iterable<SubscriptionBase> subscriptions = Iterables.<SubscriptionBase>concat(subscriptionInternalApi.getSubscriptionsForAccount(context).values());
- baseSubscriptionsToConsider = Iterables.<SubscriptionBase>filter(subscriptions,
+ final Map<UUID, List<SubscriptionBase>> subscriptions = subscriptionInternalApi.getSubscriptionsForAccount(context);
+ baseSubscriptionsToConsider = Iterables.<SubscriptionBase>filter(Iterables.<SubscriptionBase>concat(subscriptions.values()),
new Predicate<SubscriptionBase>() {
@Override
public boolean apply(final SubscriptionBase input) {
@@ -211,6 +214,7 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
!EntitlementState.CANCELLED.equals(input.getState());
}
});
+ eventsStreams = Iterables.<EventsStream>concat(eventsStreamBuilder.buildForAccount(subscriptions, context).getEventsStreams().values());
} else if (BlockingStateType.SUBSCRIPTION.equals(blockingStateType)) {
// We're coming from getBlockingHistoryForService / getBlockingAll
final SubscriptionBase subscription = subscriptionInternalApi.getSubscriptionFromId(blockableId, context);
@@ -219,6 +223,7 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
if (ProductCategory.ADD_ON.equals(subscription.getCategory())) {
final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(subscription.getBundleId(), context);
baseSubscriptionsToConsider = ImmutableList.<SubscriptionBase>of(baseSubscription);
+ eventsStreams = ImmutableList.<EventsStream>of(eventsStreamBuilder.buildForEntitlement(baseSubscription, context));
} else {
// blockable id points to a base or standalone subscription, there is nothing to do
// Simply return the sorted list
@@ -232,21 +237,32 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
} catch (SubscriptionBaseApiException e) {
log.error("Error retrieving subscriptions for account record id " + context.getAccountRecordId(), e);
throw new RuntimeException(e);
+ } catch (EntitlementApiException e) {
+ log.error("Error computing blocking states for addons for account record id " + context.getAccountRecordId(), e);
+ throw new RuntimeException(e);
}
+ return addBlockingStatesNotOnDisk(blockableId, blockingStateType, blockingStatesOnDiskCopy, baseSubscriptionsToConsider, eventsStreams);
+ }
+
+ protected List<BlockingState> addBlockingStatesNotOnDisk(@Nullable final UUID blockableId,
+ @Nullable final BlockingStateType blockingStateType,
+ final Collection<BlockingState> blockingStatesOnDiskCopy,
+ final Iterable<SubscriptionBase> baseSubscriptionsToConsider,
+ final Iterable<EventsStream> eventsStreams) {
// Retrieve the cancellation blocking state on disk, if it exists (will be used later)
final BlockingState cancellationBlockingStateOnDisk = findEntitlementCancellationBlockingState(blockableId, blockingStatesOnDiskCopy);
// Compute the blocking states not on disk for all base subscriptions
final DateTime now = clock.getUTCNow();
for (final SubscriptionBase baseSubscription : baseSubscriptionsToConsider) {
- final EventsStream eventsStream;
- try {
- eventsStream = eventsStreamBuilder.buildForEntitlement(baseSubscription.getId(), context);
- } catch (EntitlementApiException e) {
- log.error("Error computing blocking states for addons for account record id " + context.getAccountRecordId(), e);
- throw new RuntimeException(e);
- }
+ final EventsStream eventsStream = Iterables.<EventsStream>find(eventsStreams,
+ new Predicate<EventsStream>() {
+ @Override
+ public boolean apply(final EventsStream input) {
+ return input.getSubscription().getId().equals(baseSubscription.getId());
+ }
+ });
// First, check to see if the base entitlement is cancelled. If so, cancel the
final Collection<BlockingState> blockingStatesNotOnDisk = eventsStream.computeAddonsBlockingStatesForFutureSubscriptionBaseEvents();
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventsStreamBuilder.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventsStreamBuilder.java
index 0c6e8eb..f9f9cfb 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventsStreamBuilder.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EventsStreamBuilder.java
@@ -16,12 +16,19 @@
package com.ning.billing.entitlement.engine.core;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
+import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
+import org.skife.jdbi.v2.IDBI;
+
import com.ning.billing.ObjectType;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
@@ -29,48 +36,61 @@ import com.ning.billing.account.api.AccountInternalApi;
import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.AccountEventsStreams;
import com.ning.billing.entitlement.EntitlementService;
-import com.ning.billing.entitlement.api.BlockingApiException;
+import com.ning.billing.entitlement.EventsStream;
import com.ning.billing.entitlement.api.BlockingState;
import com.ning.billing.entitlement.api.BlockingStateType;
import com.ning.billing.entitlement.api.EntitlementApiException;
+import com.ning.billing.entitlement.api.svcs.DefaultAccountEventsStreams;
import com.ning.billing.entitlement.block.BlockingChecker;
-import com.ning.billing.entitlement.block.BlockingChecker.BlockingAggregator;
-import com.ning.billing.entitlement.dao.BlockingStateDao;
+import com.ning.billing.entitlement.dao.DefaultBlockingStateDao;
+import com.ning.billing.entitlement.dao.OptimizedProxyBlockingStateDao;
import com.ning.billing.subscription.api.SubscriptionBase;
import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.callcontext.TenantContext;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.google.common.base.Objects;
import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import static com.ning.billing.entitlement.dao.ProxyBlockingStateDao.BLOCKING_STATE_ORDERING;
+
@Singleton
public class EventsStreamBuilder {
private final AccountInternalApi accountInternalApi;
private final SubscriptionBaseInternalApi subscriptionInternalApi;
private final BlockingChecker checker;
- private final BlockingStateDao blockingStateDao;
+ private final OptimizedProxyBlockingStateDao blockingStateDao;
+ private final DefaultBlockingStateDao defaultBlockingStateDao;
private final Clock clock;
private final InternalCallContextFactory internalCallContextFactory;
@Inject
public EventsStreamBuilder(final AccountInternalApi accountInternalApi, final SubscriptionBaseInternalApi subscriptionInternalApi,
- final BlockingChecker checker, final BlockingStateDao blockingStateDao,
- final Clock clock, final InternalCallContextFactory internalCallContextFactory) {
+ final BlockingChecker checker, final IDBI dbi, final Clock clock,
+ final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao,
+ final InternalCallContextFactory internalCallContextFactory) {
this.accountInternalApi = accountInternalApi;
this.subscriptionInternalApi = subscriptionInternalApi;
this.checker = checker;
- this.blockingStateDao = blockingStateDao;
this.clock = clock;
this.internalCallContextFactory = internalCallContextFactory;
+
+ this.defaultBlockingStateDao = new DefaultBlockingStateDao(dbi, clock, cacheControllerDispatcher, nonEntityDao);
+ this.blockingStateDao = new OptimizedProxyBlockingStateDao(this, subscriptionInternalApi, dbi, clock, cacheControllerDispatcher, nonEntityDao);
}
public EventsStream refresh(final EventsStream eventsStream, final TenantContext tenantContext) throws EntitlementApiException {
- return buildForEntitlement(eventsStream.getSubscription().getId(), tenantContext);
+ return buildForEntitlement(eventsStream.getEntitlementId(), tenantContext);
}
public EventsStream buildForBaseSubscription(final UUID bundleId, final TenantContext tenantContext) throws EntitlementApiException {
@@ -90,6 +110,107 @@ public class EventsStreamBuilder {
return buildForEntitlement(entitlementId, internalTenantContext);
}
+ public AccountEventsStreams buildForAccount(final InternalTenantContext internalTenantContext) throws EntitlementApiException {
+ // Retrieve the subscriptions (map bundle id -> subscriptions)
+ final Map<UUID, List<SubscriptionBase>> subscriptions = subscriptionInternalApi.getSubscriptionsForAccount(internalTenantContext);
+ return buildForAccount(subscriptions, internalTenantContext);
+ }
+
+ // Special signature for ProxyBlockingStateDao to save a DAO call
+ public AccountEventsStreams buildForAccount(final Map<UUID, List<SubscriptionBase>> subscriptions, final InternalTenantContext internalTenantContext) throws EntitlementApiException {
+ // Retrieve the account
+ final Account account;
+ try {
+ account = accountInternalApi.getAccountByRecordId(internalTenantContext.getAccountRecordId(), internalTenantContext);
+ } catch (AccountApiException e) {
+ throw new EntitlementApiException(e);
+ }
+
+ return buildForAccount(account, subscriptions, internalTenantContext);
+ }
+
+ private AccountEventsStreams buildForAccount(final Account account, final Map<UUID, List<SubscriptionBase>> subscriptions, final InternalTenantContext internalTenantContext) throws EntitlementApiException {
+ if (subscriptions.isEmpty()) {
+ // Bail early
+ return new DefaultAccountEventsStreams(account);
+ }
+
+ // Retrieve the bundles
+ final List<SubscriptionBaseBundle> bundles = subscriptionInternalApi.getBundlesForAccount(account.getId(), internalTenantContext);
+ // Map bundle id -> bundles
+ final Map<UUID, SubscriptionBaseBundle> bundlesPerId = new HashMap<UUID, SubscriptionBaseBundle>();
+ for (final SubscriptionBaseBundle bundle : bundles) {
+ bundlesPerId.put(bundle.getId(), bundle);
+ }
+
+ // Retrieve the blocking states
+ final List<BlockingState> blockingStatesForAccount = BLOCKING_STATE_ORDERING.immutableSortedCopy(defaultBlockingStateDao.getBlockingAllForAccountRecordId(internalTenantContext));
+
+ // Optimization: build lookup tables for entitlement states
+ final List<BlockingState> accountEntitlementStates = new LinkedList<BlockingState>();
+ final Map<UUID, List<BlockingState>> entitlementStatesPerSubscription = new HashMap<UUID, List<BlockingState>>();
+ final Map<UUID, List<BlockingState>> entitlementStatesPerBundle = new HashMap<UUID, List<BlockingState>>();
+ for (final BlockingState blockingState : blockingStatesForAccount) {
+ if (!EntitlementService.ENTITLEMENT_SERVICE_NAME.equals(blockingState.getService())) {
+ continue;
+ } else if (BlockingStateType.SUBSCRIPTION.equals(blockingState.getType())) {
+ if (entitlementStatesPerSubscription.get(blockingState.getBlockedId()) == null) {
+ entitlementStatesPerSubscription.put(blockingState.getBlockedId(), new LinkedList<BlockingState>());
+ }
+ entitlementStatesPerSubscription.get(blockingState.getBlockedId()).add(blockingState);
+ } else if (BlockingStateType.SUBSCRIPTION_BUNDLE.equals(blockingState.getType())) {
+ if (entitlementStatesPerBundle.get(blockingState.getBlockedId()) == null) {
+ entitlementStatesPerBundle.put(blockingState.getBlockedId(), new LinkedList<BlockingState>());
+ }
+ entitlementStatesPerBundle.get(blockingState.getBlockedId()).add(blockingState);
+ } else if (BlockingStateType.ACCOUNT.equals(blockingState.getType()) &&
+ account.getId().equals(blockingState.getBlockedId())) {
+ accountEntitlementStates.add(blockingState);
+ }
+ }
+
+ // Build the EventsStream objects
+ final Map<UUID, Collection<EventsStream>> entitlementsPerBundle = new HashMap<UUID, Collection<EventsStream>>();
+ for (final UUID bundleId : subscriptions.keySet()) {
+ final SubscriptionBaseBundle bundle = bundlesPerId.get(bundleId);
+ final List<SubscriptionBase> allSubscriptionsForBundle = subscriptions.get(bundleId);
+ final SubscriptionBase baseSubscription = Iterables.<SubscriptionBase>tryFind(allSubscriptionsForBundle,
+ new Predicate<SubscriptionBase>() {
+ @Override
+ public boolean apply(final SubscriptionBase input) {
+ return ProductCategory.BASE.equals(input.getLastActiveProduct().getCategory());
+ }
+ }).orNull();
+ final List<BlockingState> bundleEntitlementStates = Objects.firstNonNull(entitlementStatesPerBundle.get(bundleId), ImmutableList.<BlockingState>of());
+
+ if (entitlementsPerBundle.get(bundleId) == null) {
+ entitlementsPerBundle.put(bundleId, new LinkedList<EventsStream>());
+ }
+
+ for (final SubscriptionBase subscription : allSubscriptionsForBundle) {
+ final List<BlockingState> subscriptionBlockingStatesOnDisk = Objects.firstNonNull(entitlementStatesPerSubscription.get(subscription.getId()), ImmutableList.<BlockingState>of());
+
+ // We cannot use blockingStatesForAccount here: we need subscriptionEntitlementStates to contain the events not on disk when building an EventsStream
+ // for an add-on - which means going through the magic of ProxyBlockingStateDao, which will recursively
+ // create EventsStream objects. To avoid an infinite recursion, bypass ProxyBlockingStateDao when it's not
+ // needed, i.e. if this EventStream is for a standalone or a base subscription
+ final List<BlockingState> subscriptionEntitlementStates = (baseSubscription == null || subscription.getId().equals(baseSubscription.getId())) ?
+ subscriptionBlockingStatesOnDisk :
+ blockingStateDao.getBlockingHistoryForService(subscriptionBlockingStatesOnDisk,
+ bundle,
+ baseSubscription,
+ subscription,
+ allSubscriptionsForBundle,
+ internalTenantContext);
+
+ final EventsStream eventStream = buildForEntitlement(account, bundle, baseSubscription, subscription, allSubscriptionsForBundle, subscriptionEntitlementStates, bundleEntitlementStates, accountEntitlementStates, internalTenantContext);
+ entitlementsPerBundle.get(bundleId).add(eventStream);
+ }
+ }
+
+ return new DefaultAccountEventsStreams(account, bundles, entitlementsPerBundle);
+ }
+
public EventsStream buildForEntitlement(final UUID entitlementId, final InternalTenantContext internalTenantContext) throws EntitlementApiException {
final SubscriptionBaseBundle bundle;
final SubscriptionBase subscription;
@@ -113,8 +234,29 @@ public class EventsStreamBuilder {
return buildForEntitlement(bundle, baseSubscription, subscription, allSubscriptionsForBundle, internalTenantContext);
}
+ // Special signature for ProxyBlockingStateDao to save some DAO calls
+ public EventsStream buildForEntitlement(final SubscriptionBase subscription, final InternalTenantContext internalTenantContext) throws EntitlementApiException {
+ final SubscriptionBaseBundle bundle;
+ try {
+ bundle = subscriptionInternalApi.getBundleFromId(subscription.getBundleId(), internalTenantContext);
+ } catch (SubscriptionBaseApiException e) {
+ throw new EntitlementApiException(e);
+ }
+
+ final List<SubscriptionBase> allSubscriptionsForBundle = subscriptionInternalApi.getSubscriptionsForBundle(subscription.getBundleId(), internalTenantContext);
+ return buildForEntitlement(bundle, subscription, subscription, allSubscriptionsForBundle, internalTenantContext);
+ }
+
+ // Special signature for OptimizedProxyBlockingStateDao to save some DAO calls
+ public EventsStream buildForEntitlement(final SubscriptionBaseBundle bundle,
+ final SubscriptionBase subscription,
+ final List<SubscriptionBase> allSubscriptionsForBundle,
+ final InternalTenantContext internalTenantContext) throws EntitlementApiException {
+ return buildForEntitlement(bundle, subscription, subscription, allSubscriptionsForBundle, internalTenantContext);
+ }
+
private EventsStream buildForEntitlement(final SubscriptionBaseBundle bundle,
- final SubscriptionBase baseSubscription,
+ @Nullable final SubscriptionBase baseSubscription,
final SubscriptionBase subscription,
final List<SubscriptionBase> allSubscriptionsForBundle,
final InternalTenantContext internalTenantContext) throws EntitlementApiException {
@@ -125,27 +267,45 @@ public class EventsStreamBuilder {
throw new EntitlementApiException(e);
}
- final List<BlockingState> subscriptionEntitlementStates = blockingStateDao.getBlockingHistoryForService(subscription.getId(), BlockingStateType.SUBSCRIPTION, EntitlementService.ENTITLEMENT_SERVICE_NAME, internalTenantContext);
- final List<BlockingState> bundleEntitlementStates = blockingStateDao.getBlockingHistoryForService(bundle.getId(), BlockingStateType.SUBSCRIPTION_BUNDLE, EntitlementService.ENTITLEMENT_SERVICE_NAME, internalTenantContext);
- final List<BlockingState> accountEntitlementStates = blockingStateDao.getBlockingHistoryForService(account.getId(), BlockingStateType.ACCOUNT, EntitlementService.ENTITLEMENT_SERVICE_NAME, internalTenantContext);
+ final List<BlockingState> bundleEntitlementStates = BLOCKING_STATE_ORDERING.immutableSortedCopy(defaultBlockingStateDao.getBlockingHistoryForService(bundle.getId(), BlockingStateType.SUBSCRIPTION_BUNDLE, EntitlementService.ENTITLEMENT_SERVICE_NAME, internalTenantContext));
+ final List<BlockingState> accountEntitlementStates = BLOCKING_STATE_ORDERING.immutableSortedCopy(defaultBlockingStateDao.getBlockingHistoryForService(account.getId(), BlockingStateType.ACCOUNT, EntitlementService.ENTITLEMENT_SERVICE_NAME, internalTenantContext));
+ final ImmutableList<BlockingState> subscriptionEntitlementStatesOnDisk = BLOCKING_STATE_ORDERING.immutableSortedCopy(defaultBlockingStateDao.getBlockingHistoryForService(subscription.getId(), BlockingStateType.SUBSCRIPTION, EntitlementService.ENTITLEMENT_SERVICE_NAME, internalTenantContext));
- final BlockingAggregator blockingAggregator;
- try {
- blockingAggregator = checker.getBlockedStatus(subscription, internalTenantContext);
- } catch (BlockingApiException e) {
- throw new EntitlementApiException(e);
- }
+ // We need subscriptionEntitlementStates to contain the events not on disk when building an EventsStream
+ // for an add-on - which means going through the magic of ProxyBlockingStateDao, which will recursively
+ // create EventsStream objects. To avoid an infinite recursion, bypass ProxyBlockingStateDao when it's not
+ // needed, i.e. if this EventStream is for a standalone or a base subscription
+ final List<BlockingState> subscriptionEntitlementStates = (baseSubscription == null || subscription.getId().equals(baseSubscription.getId())) ?
+ subscriptionEntitlementStatesOnDisk :
+ blockingStateDao.getBlockingHistoryForService(subscriptionEntitlementStatesOnDisk,
+ bundle,
+ baseSubscription,
+ subscription,
+ allSubscriptionsForBundle,
+ internalTenantContext);
- return new EventsStream(account,
- bundle,
- subscriptionEntitlementStates,
- bundleEntitlementStates,
- accountEntitlementStates,
- blockingAggregator,
- baseSubscription,
- subscription,
- allSubscriptionsForBundle,
- internalTenantContext,
- clock.getUTCNow());
+ return buildForEntitlement(account, bundle, baseSubscription, subscription, allSubscriptionsForBundle, subscriptionEntitlementStates, bundleEntitlementStates, accountEntitlementStates, internalTenantContext);
+ }
+
+ private EventsStream buildForEntitlement(final Account account,
+ final SubscriptionBaseBundle bundle,
+ @Nullable final SubscriptionBase baseSubscription,
+ final SubscriptionBase subscription,
+ final List<SubscriptionBase> allSubscriptionsForBundle,
+ final List<BlockingState> subscriptionEntitlementStates,
+ final List<BlockingState> bundleEntitlementStates,
+ final List<BlockingState> accountEntitlementStates,
+ final InternalTenantContext internalTenantContext) throws EntitlementApiException {
+ return new DefaultEventsStream(account,
+ bundle,
+ subscriptionEntitlementStates,
+ bundleEntitlementStates,
+ accountEntitlementStates,
+ checker,
+ baseSubscription,
+ subscription,
+ allSubscriptionsForBundle,
+ internalTenantContext,
+ clock.getUTCNow());
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java b/entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java
index d95248b..975419d 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java
@@ -19,11 +19,13 @@ package com.ning.billing.entitlement.glue;
import org.skife.config.ConfigSource;
import com.ning.billing.entitlement.DefaultEntitlementService;
+import com.ning.billing.entitlement.EntitlementInternalApi;
import com.ning.billing.entitlement.EntitlementService;
import com.ning.billing.entitlement.api.DefaultEntitlementApi;
import com.ning.billing.entitlement.api.DefaultSubscriptionApi;
import com.ning.billing.entitlement.api.EntitlementApi;
import com.ning.billing.entitlement.api.SubscriptionApi;
+import com.ning.billing.entitlement.api.svcs.DefaultEntitlementInternalApi;
import com.ning.billing.entitlement.api.svcs.DefaultInternalBlockingApi;
import com.ning.billing.entitlement.block.BlockingChecker;
import com.ning.billing.entitlement.block.DefaultBlockingChecker;
@@ -38,7 +40,6 @@ import com.google.inject.AbstractModule;
public class DefaultEntitlementModule extends AbstractModule implements EntitlementModule {
-
public DefaultEntitlementModule(final ConfigSource configSource) {
}
@@ -47,6 +48,7 @@ public class DefaultEntitlementModule extends AbstractModule implements Entitlem
installBlockingStateDao();
installBlockingApi();
installEntitlementApi();
+ installEntitlementInternalApi();
installSubscriptionApi();
installBlockingChecker();
bind(EntitlementService.class).to(DefaultEntitlementService.class).asEagerSingleton();
@@ -70,6 +72,11 @@ public class DefaultEntitlementModule extends AbstractModule implements Entitlem
}
@Override
+ public void installEntitlementInternalApi() {
+ bind(EntitlementInternalApi.class).to(DefaultEntitlementInternalApi.class).asEagerSingleton();
+ }
+
+ @Override
public void installSubscriptionApi() {
bind(SubscriptionApi.class).to(DefaultSubscriptionApi.class).asEagerSingleton();
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/block/MockBlockingChecker.java b/entitlement/src/test/java/com/ning/billing/entitlement/block/MockBlockingChecker.java
index 1a97df2..c5232db 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/block/MockBlockingChecker.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/block/MockBlockingChecker.java
@@ -16,17 +16,19 @@
package com.ning.billing.entitlement.block;
+import java.util.List;
import java.util.UUID;
import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.entitlement.api.Blockable;
import com.ning.billing.entitlement.api.BlockingApiException;
+import com.ning.billing.entitlement.api.BlockingState;
import com.ning.billing.entitlement.api.BlockingStateType;
public class MockBlockingChecker implements BlockingChecker {
@Override
- public BlockingAggregator getBlockedStatus(final Blockable blockable, final InternalTenantContext context) throws BlockingApiException {
+ public BlockingAggregator getBlockedStatus(final List<BlockingState> accountEntitlementStates, final List<BlockingState> bundleEntitlementStates, final List<BlockingState> subscriptionEntitlementStates, final InternalTenantContext internalTenantContext) {
return null;
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/block/TestBlockingApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/block/TestBlockingApi.java
index b17e7d8..57073a4 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/block/TestBlockingApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/block/TestBlockingApi.java
@@ -23,11 +23,15 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.ning.billing.account.api.Account;
import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.callcontext.InternalCallContext;
import com.ning.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
import com.ning.billing.entitlement.api.BlockingState;
import com.ning.billing.entitlement.api.BlockingStateType;
import com.ning.billing.junction.DefaultBlockingState;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.UserType;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
@@ -77,6 +81,9 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
final boolean blockEntitlement = false;
final boolean blockBilling = false;
+ final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), "TestBlockingApi", CallOrigin.TEST, UserType.SYSTEM, UUID.randomUUID());
+
testListener.pushExpectedEvent(NextEvent.BLOCK);
final BlockingState state1 = new DefaultBlockingState(uuid, BlockingStateType.ACCOUNT, overdueStateName, service, blockChange, blockEntitlement, blockBilling, clock.getUTCNow());
blockingInternalApi.setBlockingState(state1, internalCallContext);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java
index a0c387c..78ba189 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -29,6 +29,7 @@ import org.testng.annotations.Test;
import com.ning.billing.account.api.Account;
import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.catalog.api.BillingActionPolicy;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
@@ -36,6 +37,7 @@ import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.EntitlementService;
import com.ning.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
+import com.ning.billing.entitlement.EventsStream;
import com.ning.billing.entitlement.api.BlockingState;
import com.ning.billing.entitlement.api.BlockingStateType;
import com.ning.billing.entitlement.api.DefaultEntitlement;
@@ -46,6 +48,8 @@ import com.ning.billing.entitlement.api.EntitlementApiException;
import com.ning.billing.entitlement.dao.BlockingStateSqlDao;
import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
@@ -354,7 +358,14 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
// Test the "read" path
private void checkFutureBlockingStatesToCancel(final DefaultEntitlement baseEntitlement, @Nullable final DefaultEntitlement addOnEntitlement, @Nullable final DateTime effectiveCancellationDateTime) throws EntitlementApiException {
- final Collection<BlockingState> blockingStatesForCancellation = computeFutureBlockingStatesForAssociatedAddons(baseEntitlement);
+ final Collection<BlockingState> blockingStatesForCancellationViaEntitlement = computeFutureBlockingStatesForAssociatedAddonsViaEntitlement(baseEntitlement);
+ doCheckFutureBlockingStatesToCancel(addOnEntitlement, effectiveCancellationDateTime, blockingStatesForCancellationViaEntitlement);
+
+ final Collection<BlockingState> blockingStatesForCancellationViaAccount = computeFutureBlockingStatesForAssociatedAddonsViaAccount(baseEntitlement);
+ doCheckFutureBlockingStatesToCancel(addOnEntitlement, effectiveCancellationDateTime, blockingStatesForCancellationViaAccount);
+ }
+
+ private void doCheckFutureBlockingStatesToCancel(final DefaultEntitlement addOnEntitlement, final DateTime effectiveCancellationDateTime, final Collection<BlockingState> blockingStatesForCancellation) {
if (addOnEntitlement == null || effectiveCancellationDateTime == null) {
Assert.assertEquals(blockingStatesForCancellation.size(), 0);
} else {
@@ -370,7 +381,14 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
// Test the "write" path
private void checkActualBlockingStatesToCancel(final DefaultEntitlement baseEntitlement, final DefaultEntitlement addOnEntitlement, @Nullable final DateTime effectiveCancellationDateTime, final boolean approximateDateCheck) throws EntitlementApiException {
- final Collection<BlockingState> blockingStatesForCancellation = computeBlockingStatesForAssociatedAddons(baseEntitlement, Objects.firstNonNull(effectiveCancellationDateTime, initialDate.toDateTimeAtStartOfDay()));
+ final Collection<BlockingState> blockingStatesForCancellationViaEntitlement = computeBlockingStatesForAssociatedAddonsViaEntitlement(baseEntitlement, Objects.firstNonNull(effectiveCancellationDateTime, initialDate.toDateTimeAtStartOfDay()));
+ doCheckActualBlockingStatesToCancel(addOnEntitlement, effectiveCancellationDateTime, approximateDateCheck, blockingStatesForCancellationViaEntitlement);
+
+ final Collection<BlockingState> blockingStatesForCancellationViaAccount = computeBlockingStatesForAssociatedAddonsViaAccount(baseEntitlement, Objects.firstNonNull(effectiveCancellationDateTime, initialDate.toDateTimeAtStartOfDay()));
+ doCheckActualBlockingStatesToCancel(addOnEntitlement, effectiveCancellationDateTime, approximateDateCheck, blockingStatesForCancellationViaAccount);
+ }
+
+ private void doCheckActualBlockingStatesToCancel(final DefaultEntitlement addOnEntitlement, final DateTime effectiveCancellationDateTime, final boolean approximateDateCheck, final Collection<BlockingState> blockingStatesForCancellation) {
if (effectiveCancellationDateTime == null) {
Assert.assertEquals(blockingStatesForCancellation.size(), 0);
} else {
@@ -415,13 +433,37 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
Assert.assertEquals(blockingStatesForAddOn.get(0).getStateName(), DefaultEntitlementApi.ENT_STATE_CANCELLED);
}
- private Collection<BlockingState> computeFutureBlockingStatesForAssociatedAddons(final DefaultEntitlement baseEntitlement) throws EntitlementApiException {
+ private Collection<BlockingState> computeFutureBlockingStatesForAssociatedAddonsViaEntitlement(final DefaultEntitlement baseEntitlement) throws EntitlementApiException {
final EventsStream eventsStream = eventsStreamBuilder.buildForEntitlement(baseEntitlement.getId(), callContext);
return eventsStream.computeAddonsBlockingStatesForFutureSubscriptionBaseEvents();
}
- private Collection<BlockingState> computeBlockingStatesForAssociatedAddons(final DefaultEntitlement baseEntitlement, final DateTime effectiveDate) throws EntitlementApiException {
+ private Collection<BlockingState> computeFutureBlockingStatesForAssociatedAddonsViaAccount(final DefaultEntitlement baseEntitlement) throws EntitlementApiException {
+ final InternalTenantContext context = internalCallContextFactory.createInternalTenantContext(baseEntitlement.getAccountId(), callContext);
+ final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(eventsStreamBuilder.buildForAccount(context).getEventsStreams().values()),
+ new Predicate<EventsStream>() {
+ @Override
+ public boolean apply(final EventsStream input) {
+ return input.getSubscription().getId().equals(baseEntitlement.getId());
+ }
+ });
+ return eventsStream.computeAddonsBlockingStatesForFutureSubscriptionBaseEvents();
+ }
+
+ private Collection<BlockingState> computeBlockingStatesForAssociatedAddonsViaEntitlement(final DefaultEntitlement baseEntitlement, final DateTime effectiveDate) throws EntitlementApiException {
final EventsStream eventsStream = eventsStreamBuilder.buildForEntitlement(baseEntitlement.getId(), callContext);
return eventsStream.computeAddonsBlockingStatesForNextSubscriptionBaseEvent(effectiveDate);
}
+
+ private Collection<BlockingState> computeBlockingStatesForAssociatedAddonsViaAccount(final DefaultEntitlement baseEntitlement, final DateTime effectiveDate) throws EntitlementApiException {
+ final InternalTenantContext context = internalCallContextFactory.createInternalTenantContext(baseEntitlement.getAccountId(), callContext);
+ final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(eventsStreamBuilder.buildForAccount(context).getEventsStreams().values()),
+ new Predicate<EventsStream>() {
+ @Override
+ public boolean apply(final EventsStream input) {
+ return input.getSubscription().getId().equals(baseEntitlement.getId());
+ }
+ });
+ return eventsStream.computeAddonsBlockingStatesForNextSubscriptionBaseEvent(effectiveDate);
+ }
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java b/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
index 2227fd6..99711d9 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
@@ -52,6 +52,7 @@ import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
import com.ning.billing.subscription.api.SubscriptionBaseService;
import com.ning.billing.subscription.engine.core.DefaultSubscriptionBaseService;
import com.ning.billing.tag.TagInternalApi;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.svcsapi.bus.BusService;
import com.ning.billing.util.tag.dao.TagDao;
@@ -106,6 +107,8 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
protected EntitlementUtils entitlementUtils;
@Inject
protected EventsStreamBuilder eventsStreamBuilder;
+ @Inject
+ protected InternalCallContextFactory internalCallContextFactory;
protected Catalog catalog;
invoice/pom.xml 2(+1 -1)
diff --git a/invoice/pom.xml b/invoice/pom.xml
index e26016f..9bc2960 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-invoice</artifactId>
jaxrs/pom.xml 2(+1 -1)
diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index c4b1329..e9d7021 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-jaxrs</artifactId>
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/AccountApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/AccountApiExceptionMapper.java
index 26a1908..a9484fb 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/AccountApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/AccountApiExceptionMapper.java
@@ -54,8 +54,10 @@ public class AccountApiExceptionMapper extends ExceptionMapperBase implements Ex
return buildBadRequestResponse(exception, uriInfo);
} else if (exception.getCode() == ErrorCode.ACCOUNT_UPDATE_FAILED.getCode()) {
return buildInternalErrorResponse(exception, uriInfo);
+ } else if (exception.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_RECORD_ID.getCode()) {
+ return buildNotFoundResponse(exception, uriInfo);
} else {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/BlockingApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/BlockingApiExceptionMapper.java
index 7f23095..aed9c10 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/BlockingApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/BlockingApiExceptionMapper.java
@@ -37,6 +37,6 @@ public class BlockingApiExceptionMapper extends ExceptionMapperBase implements E
@Override
public Response toResponse(final BlockingApiException exception) {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/CatalogApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/CatalogApiExceptionMapper.java
index d5a464d..fe85c6f 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/CatalogApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/CatalogApiExceptionMapper.java
@@ -37,6 +37,6 @@ public class CatalogApiExceptionMapper extends ExceptionMapperBase implements Ex
@Override
public Response toResponse(final CatalogApiException exception) {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EmailApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EmailApiExceptionMapper.java
index e619556..ffdf1c9 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EmailApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EmailApiExceptionMapper.java
@@ -37,6 +37,6 @@ public class EmailApiExceptionMapper extends ExceptionMapperBase implements Exce
@Override
public Response toResponse(final EmailApiException exception) {
- return buildInternalErrorResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EntitlementApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EntitlementApiExceptionMapper.java
index 5dcfa3b..c4506cb 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EntitlementApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EntitlementApiExceptionMapper.java
@@ -45,7 +45,7 @@ public class EntitlementApiExceptionMapper extends ExceptionMapperBase implement
} else if (exception.getCode() == ErrorCode.SUB_INVALID_SUBSCRIPTION_ID.getCode()) {
return buildNotFoundResponse(exception, uriInfo);
} else {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EntityPersistenceExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EntityPersistenceExceptionMapper.java
index d7c6194..f9301b7 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EntityPersistenceExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/EntityPersistenceExceptionMapper.java
@@ -37,6 +37,6 @@ public class EntityPersistenceExceptionMapper extends ExceptionMapperBase implem
@Override
public Response toResponse(final EntityPersistenceException exception) {
- return buildInternalErrorResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/ExceptionMapperBase.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/ExceptionMapperBase.java
index 2c82fa6..c070c79 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/ExceptionMapperBase.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/ExceptionMapperBase.java
@@ -24,7 +24,22 @@ import javax.ws.rs.core.UriInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.entitlement.api.BlockingApiException;
+import com.ning.billing.entitlement.api.EntitlementApiException;
+import com.ning.billing.entitlement.api.SubscriptionApiException;
+import com.ning.billing.entity.EntityPersistenceException;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.jaxrs.json.BillingExceptionJson;
+import com.ning.billing.overdue.OverdueApiException;
+import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.subscription.api.SubscriptionBillingApiException;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseRepairException;
+import com.ning.billing.util.api.TagApiException;
+import com.ning.billing.util.api.TagDefinitionApiException;
+import com.ning.billing.util.email.EmailApiException;
import com.ning.billing.util.jackson.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -34,6 +49,67 @@ public abstract class ExceptionMapperBase {
private static final Logger log = LoggerFactory.getLogger(ExceptionMapperBase.class);
private static final ObjectMapper mapper = new ObjectMapper();
+ protected Response fallback(final Exception exception, final UriInfo uriInfo) {
+ if (exception.getCause() == null) {
+ return buildBadRequestResponse(exception, uriInfo);
+ } else {
+ return doFallback(exception, uriInfo);
+ }
+ }
+
+ private Response doFallback(final Exception exception, final UriInfo uriInfo) {
+ if (exception.getCause() == null || !(exception.getCause() instanceof BillingExceptionBase)) {
+ return buildBadRequestResponse(exception, uriInfo);
+ }
+
+ final BillingExceptionBase cause = (BillingExceptionBase) exception.getCause();
+ if (cause instanceof AccountApiException) {
+ final AccountApiExceptionMapper mapper = new AccountApiExceptionMapper(uriInfo);
+ return mapper.toResponse((AccountApiException) cause);
+ } else if (cause instanceof BlockingApiException) {
+ final BlockingApiExceptionMapper mapper = new BlockingApiExceptionMapper(uriInfo);
+ return mapper.toResponse((BlockingApiException) cause);
+ } else if (cause instanceof CatalogApiException) {
+ final CatalogApiExceptionMapper mapper = new CatalogApiExceptionMapper(uriInfo);
+ return mapper.toResponse((CatalogApiException) cause);
+ } else if (cause instanceof EmailApiException) {
+ final EmailApiExceptionMapper mapper = new EmailApiExceptionMapper(uriInfo);
+ return mapper.toResponse((EmailApiException) cause);
+ } else if (cause instanceof EntitlementApiException) {
+ final EntitlementApiExceptionMapper mapper = new EntitlementApiExceptionMapper(uriInfo);
+ return mapper.toResponse((EntitlementApiException) cause);
+ } else if (cause instanceof EntityPersistenceException) {
+ final EntityPersistenceExceptionMapper mapper = new EntityPersistenceExceptionMapper(uriInfo);
+ return mapper.toResponse((EntityPersistenceException) cause);
+ } else if (cause instanceof InvoiceApiException) {
+ final InvoiceApiExceptionMapper mapper = new InvoiceApiExceptionMapper(uriInfo);
+ return mapper.toResponse((InvoiceApiException) cause);
+ } else if (cause instanceof OverdueApiException) {
+ final OverdueApiExceptionMapper mapper = new OverdueApiExceptionMapper(uriInfo);
+ return mapper.toResponse((OverdueApiException) cause);
+ } else if (cause instanceof PaymentApiException) {
+ final PaymentApiExceptionMapper mapper = new PaymentApiExceptionMapper(uriInfo);
+ return mapper.toResponse((PaymentApiException) cause);
+ } else if (cause instanceof SubscriptionApiException) {
+ final SubscriptionApiExceptionMapper mapper = new SubscriptionApiExceptionMapper(uriInfo);
+ return mapper.toResponse((SubscriptionApiException) cause);
+ } else if (cause instanceof SubscriptionBillingApiException) {
+ final SubscriptionBillingApiExceptionMapper mapper = new SubscriptionBillingApiExceptionMapper(uriInfo);
+ return mapper.toResponse((SubscriptionBillingApiException) cause);
+ } else if (cause instanceof SubscriptionBaseRepairException) {
+ final SubscriptionRepairExceptionMapper mapper = new SubscriptionRepairExceptionMapper(uriInfo);
+ return mapper.toResponse((SubscriptionBaseRepairException) cause);
+ } else if (cause instanceof TagApiException) {
+ final TagApiExceptionMapper mapper = new TagApiExceptionMapper(uriInfo);
+ return mapper.toResponse((TagApiException) cause);
+ } else if (cause instanceof TagDefinitionApiException) {
+ final TagDefinitionApiExceptionMapper mapper = new TagDefinitionApiExceptionMapper(uriInfo);
+ return mapper.toResponse((TagDefinitionApiException) cause);
+ } else {
+ return buildBadRequestResponse(cause, uriInfo);
+ }
+ }
+
protected Response buildConflictingRequestResponse(final Exception e, final UriInfo uriInfo) {
// Log the full stacktrace
log.warn("Conflicting request", e);
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/InvoiceApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/InvoiceApiExceptionMapper.java
index 6dc12e4..8f19f44 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/InvoiceApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/InvoiceApiExceptionMapper.java
@@ -69,7 +69,7 @@ public class InvoiceApiExceptionMapper extends ExceptionMapperBase implements Ex
} else if (exception.getCode() == ErrorCode.EXTERNAL_CHARGE_AMOUNT_INVALID.getCode()) {
return buildBadRequestResponse(exception, uriInfo);
} else {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/OverdueApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/OverdueApiExceptionMapper.java
index 13b5e44..061f0f0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/OverdueApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/OverdueApiExceptionMapper.java
@@ -37,6 +37,6 @@ public class OverdueApiExceptionMapper extends ExceptionMapperBase implements Ex
@Override
public Response toResponse(final OverdueApiException exception) {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/PaymentApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/PaymentApiExceptionMapper.java
index f4678e2..e1bafc0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/PaymentApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/PaymentApiExceptionMapper.java
@@ -99,7 +99,7 @@ public class PaymentApiExceptionMapper extends ExceptionMapperBase implements Ex
} else if (exception.getCode() == ErrorCode.PAYMENT_UPD_PAYMENT_PROVIDER_ACCOUNT.getCode()) {
return buildInternalErrorResponse(exception, uriInfo);
} else {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionApiExceptionMapper.java
index cdcc153..36a9bd0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionApiExceptionMapper.java
@@ -25,7 +25,6 @@ import javax.ws.rs.ext.Provider;
import com.ning.billing.ErrorCode;
import com.ning.billing.entitlement.api.SubscriptionApiException;
-import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
@Singleton
@Provider
@@ -81,10 +80,10 @@ public class SubscriptionApiExceptionMapper extends ExceptionMapperBase implemen
return buildNotFoundResponse(exception, uriInfo);
} else if (exception.getCode() == ErrorCode.SUB_RECREATE_BAD_STATE.getCode()) {
return buildInternalErrorResponse(exception, uriInfo);
- } else if (exception.getCode() == ErrorCode.SUB_UNCANCEL_BAD_STATE.getCode()) {
+ } else if (exception.getCode() == ErrorCode.SUB_UNCANCEL_BAD_STATE.getCode()) {
return buildInternalErrorResponse(exception, uriInfo);
} else {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionBillingApiExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionBillingApiExceptionMapper.java
index 2b38fe8..b48434e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionBillingApiExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionBillingApiExceptionMapper.java
@@ -37,6 +37,6 @@ public class SubscriptionBillingApiExceptionMapper extends ExceptionMapperBase i
@Override
public Response toResponse(final SubscriptionBillingApiException exception) {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionRepairExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionRepairExceptionMapper.java
index 0947a82..f00f0c0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionRepairExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionRepairExceptionMapper.java
@@ -69,7 +69,7 @@ public class SubscriptionRepairExceptionMapper extends ExceptionMapperBase imple
} else if (exception.getCode() == ErrorCode.SUB_REPAIR_VIEW_CHANGED.getCode()) {
return buildBadRequestResponse(exception, uriInfo);
} else {
- return buildBadRequestResponse(exception, uriInfo);
+ return fallback(exception, uriInfo);
}
}
}
junction/pom.xml 2(+1 -1)
diff --git a/junction/pom.xml b/junction/pom.xml
index 3a94722..75bfa39 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-junction</artifactId>
diff --git a/junction/src/test/java/com/ning/billing/junction/JunctionTestSuiteWithEmbeddedDB.java b/junction/src/test/java/com/ning/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
index 7f98ec3..20750d0 100644
--- a/junction/src/test/java/com/ning/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
+++ b/junction/src/test/java/com/ning/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
@@ -47,6 +47,7 @@ import com.ning.billing.mock.MockAccountBuilder;
import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
import com.ning.billing.subscription.api.SubscriptionBaseService;
import com.ning.billing.subscription.engine.core.DefaultSubscriptionBaseService;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.svcsapi.bus.BusService;
import com.google.inject.Guice;
@@ -88,6 +89,8 @@ public abstract class JunctionTestSuiteWithEmbeddedDB extends GuicyKillbillTestS
protected SubscriptionBaseService subscriptionBaseService;
@Inject
protected EntitlementService entitlementService;
+ @Inject
+ protected InternalCallContextFactory internalCallContextFactory;
protected Catalog catalog;
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
index 99ed652..6aac83a 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
@@ -25,6 +25,7 @@ import org.testng.annotations.Test;
import com.ning.billing.account.api.Account;
import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.callcontext.InternalCallContext;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
@@ -60,6 +61,8 @@ public class TestDefaultInternalBillingApi extends JunctionTestSuiteWithEmbedded
clock.setDay(initialDate);
final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+
testListener.pushExpectedEvent(NextEvent.CREATE);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), initialDate, callContext);
osgi/pom.xml 2(+1 -1)
diff --git a/osgi/pom.xml b/osgi/pom.xml
index 8dec480..b8f1e44 100644
--- a/osgi/pom.xml
+++ b/osgi/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi</artifactId>
osgi-bundles/bundles/jruby/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/bundles/jruby/pom.xml b/osgi-bundles/bundles/jruby/pom.xml
index 31b2830..4ea2473 100644
--- a/osgi-bundles/bundles/jruby/pom.xml
+++ b/osgi-bundles/bundles/jruby/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-osgi-bundles</artifactId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles-jruby</artifactId>
osgi-bundles/bundles/logger/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/bundles/logger/pom.xml b/osgi-bundles/bundles/logger/pom.xml
index c2c06ce..5dbfd4d 100644
--- a/osgi-bundles/bundles/logger/pom.xml
+++ b/osgi-bundles/bundles/logger/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles-logger</artifactId>
osgi-bundles/bundles/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/bundles/pom.xml b/osgi-bundles/bundles/pom.xml
index 4f8c8cc..d412316 100644
--- a/osgi-bundles/bundles/pom.xml
+++ b/osgi-bundles/bundles/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-all-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles</artifactId>
diff --git a/osgi-bundles/bundles/webconsolebranding/pom.xml b/osgi-bundles/bundles/webconsolebranding/pom.xml
index b5133e7..f9b0f21 100644
--- a/osgi-bundles/bundles/webconsolebranding/pom.xml
+++ b/osgi-bundles/bundles/webconsolebranding/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles-webconsolebranding</artifactId>
osgi-bundles/defaultbundles/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/defaultbundles/pom.xml b/osgi-bundles/defaultbundles/pom.xml
index a72ee5f..1a093ba 100644
--- a/osgi-bundles/defaultbundles/pom.xml
+++ b/osgi-bundles/defaultbundles/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-all-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles-defaultbundles</artifactId>
osgi-bundles/libs/killbill/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/libs/killbill/pom.xml b/osgi-bundles/libs/killbill/pom.xml
index 267a987..8f25117 100644
--- a/osgi-bundles/libs/killbill/pom.xml
+++ b/osgi-bundles/libs/killbill/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-lib-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles-lib-killbill</artifactId>
osgi-bundles/libs/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/libs/pom.xml b/osgi-bundles/libs/pom.xml
index 1bb6ae2..b086770 100644
--- a/osgi-bundles/libs/pom.xml
+++ b/osgi-bundles/libs/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-all-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-lib-bundles</artifactId>
osgi-bundles/libs/slf4j-osgi/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/libs/slf4j-osgi/pom.xml b/osgi-bundles/libs/slf4j-osgi/pom.xml
index 010af7f..936e2ad 100644
--- a/osgi-bundles/libs/slf4j-osgi/pom.xml
+++ b/osgi-bundles/libs/slf4j-osgi/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-lib-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles-lib-slf4j-osgi</artifactId>
osgi-bundles/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/pom.xml b/osgi-bundles/pom.xml
index a3a5e6b..3143f43 100644
--- a/osgi-bundles/pom.xml
+++ b/osgi-bundles/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-all-bundles</artifactId>
osgi-bundles/tests/beatrix/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/tests/beatrix/pom.xml b/osgi-bundles/tests/beatrix/pom.xml
index cf066e8..c1381ab 100644
--- a/osgi-bundles/tests/beatrix/pom.xml
+++ b/osgi-bundles/tests/beatrix/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-test-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles-test-beatrix</artifactId>
osgi-bundles/tests/payment/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/tests/payment/pom.xml b/osgi-bundles/tests/payment/pom.xml
index 157f015..dae5a1b 100644
--- a/osgi-bundles/tests/payment/pom.xml
+++ b/osgi-bundles/tests/payment/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-test-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-bundles-test-payment</artifactId>
osgi-bundles/tests/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/tests/pom.xml b/osgi-bundles/tests/pom.xml
index d629b01..e67b287 100644
--- a/osgi-bundles/tests/pom.xml
+++ b/osgi-bundles/tests/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-osgi-all-bundles</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-osgi-test-bundles</artifactId>
overdue/pom.xml 2(+1 -1)
diff --git a/overdue/pom.xml b/overdue/pom.xml
index 00f74f3..91b133c 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-overdue</artifactId>
payment/pom.xml 2(+1 -1)
diff --git a/payment/pom.xml b/payment/pom.xml
index 3823ba6..d5ebace 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-payment</artifactId>
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index d69541b..860b39e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
<version>0.5.6</version>
</parent>
<artifactId>killbill</artifactId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<packaging>pom</packaging>
<name>killbill</name>
<description>Library for managing recurring subscriptions and the associated billing</description>
server/pom.xml 2(+1 -1)
diff --git a/server/pom.xml b/server/pom.xml
index 4d079a1..65f3d74 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-server</artifactId>
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java b/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
index 97201a2..b99874d 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
@@ -95,7 +95,7 @@ public class TestBundle extends TestJaxrsBase {
queryParams.put(JaxrsResource.QUERY_EXTERNAL_KEY, "56566");
uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.BUNDLES;
response = doGet(uri, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
- Assert.assertEquals(response.getStatusCode(), Status.NOT_FOUND.getStatusCode());
+ Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.BUNDLES;
response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
subscription/pom.xml 2(+1 -1)
diff --git a/subscription/pom.xml b/subscription/pom.xml
index 8b8f285..b81e255 100644
--- a/subscription/pom.xml
+++ b/subscription/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-subscription</artifactId>
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index 7aec7aa..21edeeb 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -39,10 +39,20 @@ import org.slf4j.LoggerFactory;
import com.ning.billing.ErrorCode;
import com.ning.billing.bus.api.PersistentBus;
import com.ning.billing.bus.api.PersistentBus.EventBusException;
+import com.ning.billing.callcontext.InternalCallContext;
+import com.ning.billing.callcontext.InternalTenantContext;
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.clock.Clock;
+import com.ning.billing.entity.EntityPersistenceException;
+import com.ning.billing.events.EffectiveSubscriptionInternalEvent;
+import com.ning.billing.events.RepairSubscriptionInternalEvent;
+import com.ning.billing.notificationq.api.NotificationEvent;
+import com.ning.billing.notificationq.api.NotificationQueue;
+import com.ning.billing.notificationq.api.NotificationQueueService;
+import com.ning.billing.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
+import com.ning.billing.subscription.api.SubscriptionBase;
import com.ning.billing.subscription.api.migration.AccountMigrationData;
import com.ning.billing.subscription.api.migration.AccountMigrationData.BundleMigrationData;
import com.ning.billing.subscription.api.migration.AccountMigrationData.SubscriptionMigrationData;
@@ -54,13 +64,13 @@ import com.ning.billing.subscription.api.user.DefaultRequestedSubscriptionEvent;
import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
-import com.ning.billing.subscription.api.user.SubscriptionBuilder;
import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
+import com.ning.billing.subscription.api.user.SubscriptionBuilder;
import com.ning.billing.subscription.engine.addon.AddonUtils;
import com.ning.billing.subscription.engine.core.DefaultSubscriptionBaseService;
import com.ning.billing.subscription.engine.core.SubscriptionNotificationKey;
-import com.ning.billing.subscription.engine.dao.model.SubscriptionEventModelDao;
import com.ning.billing.subscription.engine.dao.model.SubscriptionBundleModelDao;
+import com.ning.billing.subscription.engine.dao.model.SubscriptionEventModelDao;
import com.ning.billing.subscription.engine.dao.model.SubscriptionModelDao;
import com.ning.billing.subscription.events.SubscriptionBaseEvent;
import com.ning.billing.subscription.events.SubscriptionBaseEvent.EventType;
@@ -72,27 +82,20 @@ import com.ning.billing.subscription.events.user.ApiEventChange;
import com.ning.billing.subscription.events.user.ApiEventMigrateBilling;
import com.ning.billing.subscription.events.user.ApiEventType;
import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
-import com.ning.billing.notificationq.api.NotificationEvent;
-import com.ning.billing.notificationq.api.NotificationQueue;
-import com.ning.billing.notificationq.api.NotificationQueueService;
-import com.ning.billing.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
-import com.ning.billing.subscription.api.SubscriptionBase;
import com.ning.billing.util.cache.CacheControllerDispatcher;
-import com.ning.billing.callcontext.InternalCallContext;
-import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.util.dao.NonEntityDao;
-import com.ning.billing.entity.EntityPersistenceException;
import com.ning.billing.util.entity.dao.EntitySqlDao;
import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
-import com.ning.billing.events.EffectiveSubscriptionInternalEvent;
-import com.ning.billing.events.RepairSubscriptionInternalEvent;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
public class DefaultSubscriptionDao implements SubscriptionDao {
@@ -236,10 +239,9 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
return buildSubscription(shellSubscription, context);
}
-
@Override
public List<SubscriptionBase> getSubscriptions(final UUID bundleId, final InternalTenantContext context) {
- return buildBundleSubscriptions(bundleId, getSubscriptionFromBundleId(bundleId, context), context);
+ return buildBundleSubscriptions(getSubscriptionFromBundleId(bundleId, context), null, context);
}
private List<SubscriptionBase> getSubscriptionFromBundleId(final UUID bundleId, final InternalTenantContext context) {
@@ -257,13 +259,37 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
});
}
+
@Override
public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final InternalTenantContext context) {
final Map<UUID, List<SubscriptionBase>> subscriptionsFromAccountId = getSubscriptionsFromAccountId(context);
+ final List<SubscriptionBaseEvent> eventsForAccount = getEventsForAccountId(context);
+
final Map<UUID, List<SubscriptionBase>> result = new HashMap<UUID, List<SubscriptionBase>>();
for (final UUID bundleId : subscriptionsFromAccountId.keySet()) {
- result.put(bundleId, buildBundleSubscriptions(bundleId, subscriptionsFromAccountId.get(bundleId), context));
+
+ final List<SubscriptionBase> subscriptionsForBundle = subscriptionsFromAccountId.get(bundleId);
+ final Collection<UUID> subscriptionIdsForBundle = Collections2.transform(subscriptionsForBundle, new Function<SubscriptionBase, UUID>() {
+ @Override
+ public UUID apply(final SubscriptionBase input) {
+ return input.getId();
+ }
+ });
+ final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscriptions = ArrayListMultimap.create();
+
+ for (final SubscriptionBase cur : subscriptionsForBundle) {
+ final Collection<SubscriptionBaseEvent> events= Collections2.filter(eventsForAccount, new Predicate<SubscriptionBaseEvent>() {
+ @Override
+ public boolean apply(final SubscriptionBaseEvent input) {
+ return input.getSubscriptionId().equals(cur.getId());
+
+ }
+ });
+ eventsForSubscriptions.putAll(cur.getId(), ImmutableList.copyOf(events));
+ }
+
+ result.put(bundleId, buildBundleSubscriptions(subscriptionsForBundle, eventsForSubscriptions,context));
}
return result;
}
@@ -292,23 +318,6 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
return result;
}
- /*
- @Override
- public List<SubscriptionBase> getSubscriptionsForAccountAndKey(final UUID accountId,
- final String bundleKey, final InternalTenantContext callcontext) {
- return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBase>>() {
- @Override
- public List<SubscriptionBase> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
- final SubscriptionBundleModelDao bundleModel = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesFromAccountAndKey(accountId.toString(), bundleKey, callcontext);
- if (bundleModel == null) {
- return Collections.emptyList();
- }
- return getSubscriptions(bundleModel.getId(), callcontext);
- }
- });
- }
- */
-
@Override
public void updateChargedThroughDate(final DefaultSubscriptionBase subscription, final InternalCallContext context) {
final Date ctd = (subscription.getChargedThroughDate() != null) ? subscription.getChargedThroughDate().toDate() : null;
@@ -365,23 +374,12 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
@Override
public List<SubscriptionBaseEvent> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
final List<SubscriptionEventModelDao> models = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).getEventsForSubscription(subscriptionId.toString(), context);
- // Remove UNCANCEL events early on as they are not representative of a state transition but are just markers
- final Collection<SubscriptionEventModelDao> filteredModels = Collections2.filter(models, new Predicate<SubscriptionEventModelDao>() {
- @Override
- public boolean apply(@Nullable final SubscriptionEventModelDao input) {
- return input.getUserType() != ApiEventType.UNCANCEL;
- }
- });
- return new ArrayList<SubscriptionBaseEvent>(Collections2.transform(filteredModels, new Function<SubscriptionEventModelDao, SubscriptionBaseEvent>() {
- @Override
- public SubscriptionBaseEvent apply(@Nullable final SubscriptionEventModelDao input) {
- return SubscriptionEventModelDao.toSubscriptionEvent(input);
- }
- }));
+ return filterSubscriptionBaseEvents(models);
}
});
}
+
@Override
public Map<UUID, List<SubscriptionBaseEvent>> getEventsForBundle(final UUID bundleId, final InternalTenantContext context) {
return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Map<UUID, List<SubscriptionBaseEvent>>>() {
@@ -455,7 +453,6 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
});
}
-
@Override
public void recreateSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionBaseEvent> recreateEvents, final InternalCallContext context) {
transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
@@ -494,7 +491,6 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
});
}
-
@Override
public void cancelSubscription(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent cancelEvent, final InternalCallContext context, final int seqId) {
transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
@@ -557,9 +553,9 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
final UUID subscriptionId = subscription.getId();
final List<SubscriptionBaseEvent> changeEventsTweakedWithMigrateBilling = reinsertFutureMigrateBillingEventOnChangeFromTransaction(subscriptionId,
- changeEvents,
- entitySqlDaoWrapperFactory,
- context);
+ changeEvents,
+ entitySqlDaoWrapperFactory,
+ context);
cancelFutureEventsFromTransaction(subscriptionId, entitySqlDaoWrapperFactory, context);
@@ -669,6 +665,31 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
return changeEvents;
}
+ private List<SubscriptionBaseEvent> filterSubscriptionBaseEvents(final List<SubscriptionEventModelDao> models) {
+ final Collection<SubscriptionEventModelDao> filteredModels = Collections2.filter(models, new Predicate<SubscriptionEventModelDao>() {
+ @Override
+ public boolean apply(@Nullable final SubscriptionEventModelDao input) {
+ return input.getUserType() != ApiEventType.UNCANCEL;
+ }
+ });
+ return new ArrayList<SubscriptionBaseEvent>(Collections2.transform(filteredModels, new Function<SubscriptionEventModelDao, SubscriptionBaseEvent>() {
+ @Override
+ public SubscriptionBaseEvent apply(@Nullable final SubscriptionEventModelDao input) {
+ return SubscriptionEventModelDao.toSubscriptionEvent(input);
+ }
+ }));
+ }
+
+ private List<SubscriptionBaseEvent> getEventsForAccountId(final InternalTenantContext context) {
+ return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseEvent>>() {
+ @Override
+ public List<SubscriptionBaseEvent> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+ final List<SubscriptionEventModelDao> models = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).getByAccountRecordId(context);
+ return filterSubscriptionBaseEvents(models);
+ }
+ });
+ }
+
private void cancelSubscriptionFromTransaction(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent cancelEvent, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context, final int seqId)
throws EntityPersistenceException {
final UUID subscriptionId = subscription.getId();
@@ -701,7 +722,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
}
private SubscriptionEventModelDao findFutureEventFromTransaction(final UUID subscriptionId, final EntitySqlDaoWrapperFactory<EntitySqlDao> dao, final EventType type,
- @Nullable final ApiEventType apiType, final InternalCallContext context) {
+ @Nullable final ApiEventType apiType, final InternalCallContext context) {
SubscriptionEventModelDao futureEvent = null;
final Date now = clock.getUTCNow().toDate();
@@ -711,7 +732,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
(apiType == null || apiType == cur.getUserType())) {
if (futureEvent != null) {
throw new SubscriptionBaseError(String.format("Found multiple future events for type %s for subscriptions %s",
- type, subscriptionId.toString()));
+ type, subscriptionId.toString()));
}
futureEvent = cur;
// To check that there is only one such event
@@ -746,7 +767,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
bundleInput.add(input);
}
- final List<SubscriptionBase> reloadedSubscriptions = buildBundleSubscriptions(input.getBundleId(), bundleInput, context);
+ final List<SubscriptionBase> reloadedSubscriptions = buildBundleSubscriptions(bundleInput, null, context);
for (final SubscriptionBase cur : reloadedSubscriptions) {
if (cur.getId().equals(input.getId())) {
return cur;
@@ -756,7 +777,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
throw new SubscriptionBaseError("Unexpected code path in buildSubscription");
}
- private List<SubscriptionBase> buildBundleSubscriptions(final UUID bundleId, final List<SubscriptionBase> input, final InternalTenantContext context) {
+ private List<SubscriptionBase> buildBundleSubscriptions(final List<SubscriptionBase> input, @Nullable final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscription, final InternalTenantContext context) {
if (input == null || input.size() == 0) {
return Collections.emptyList();
}
@@ -778,7 +799,12 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
SubscriptionBaseEvent futureBaseEvent = null;
final List<SubscriptionBase> result = new ArrayList<SubscriptionBase>(input.size());
for (final SubscriptionBase cur : input) {
- final List<SubscriptionBaseEvent> events = getEventsForSubscription(cur.getId(), context);
+
+
+ final List<SubscriptionBaseEvent> events = eventsForSubscription != null ?
+ (List<SubscriptionBaseEvent>) eventsForSubscription.get(cur.getId()) :
+ getEventsForSubscription(cur.getId(), context);
+
SubscriptionBase reloaded = createSubscriptionForInternalUse(cur, events);
switch (cur.getCategory()) {
@@ -806,15 +832,15 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
if (createCancelEvent && reloaded.getFutureEndDate() == null) {
final DateTime now = clock.getUTCNow();
final SubscriptionBaseEvent addOnCancelEvent = new ApiEventCancel(new ApiEventBuilder()
- .setSubscriptionId(reloaded.getId())
- .setActiveVersion(((DefaultSubscriptionBase) reloaded).getActiveVersion())
- .setProcessedDate(now)
- .setEffectiveDate(futureBaseEvent.getEffectiveDate())
- .setRequestedDate(now)
- .setCreatedDate(futureBaseEvent.getCreatedDate())
- // This event is only there to indicate the ADD_ON is future canceled, but it is not there
- // on disk until the base plan cancellation becomes effective
- .setFromDisk(false));
+ .setSubscriptionId(reloaded.getId())
+ .setActiveVersion(((DefaultSubscriptionBase) reloaded).getActiveVersion())
+ .setProcessedDate(now)
+ .setEffectiveDate(futureBaseEvent.getEffectiveDate())
+ .setRequestedDate(now)
+ .setCreatedDate(futureBaseEvent.getCreatedDate())
+ // This event is only there to indicate the ADD_ON is future canceled, but it is not there
+ // on disk until the base plan cancellation becomes effective
+ .setFromDisk(false));
events.add(addOnCancelEvent);
// Finally reload subscription with full set of events
@@ -873,7 +899,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
try {
// Note: we don't send a requested change event here, but a repair event
final RepairSubscriptionInternalEvent busEvent = new DefaultRepairSubscriptionEvent(accountId, bundleId, clock.getUTCNow(),
- context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
+ context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
eventBus.postFromTransaction(busEvent, entitySqlDaoWrapperFactory.getSqlDao());
} catch (EventBusException e) {
log.warn("Failed to post repair subscription event for bundle " + bundleId, e);
@@ -922,7 +948,6 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
return null;
}
-
//
// Either records a notfication or sends a bus event is operation is immediate
//
@@ -953,7 +978,6 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
context.getUserToken(),
context.getAccountRecordId(), context.getTenantRecordId());
-
eventBus.postFromTransaction(busEvent, entitySqlDaoWrapperFactory.getSqlDao());
} catch (EventBusException e) {
log.warn("Failed to post effective event for subscription " + subscription.getId(), e);
diff --git a/subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java b/subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java
index 0c35d1c..953a2ea 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java
@@ -23,6 +23,7 @@ import com.ning.billing.glue.SubscriptionModule;
import com.ning.billing.subscription.alignment.MigrationPlanAligner;
import com.ning.billing.subscription.alignment.PlanAligner;
import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
import com.ning.billing.subscription.api.SubscriptionBaseService;
import com.ning.billing.subscription.api.migration.DefaultSubscriptionBaseMigrationApi;
import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi;
@@ -40,7 +41,6 @@ import com.ning.billing.subscription.engine.dao.DefaultSubscriptionDao;
import com.ning.billing.subscription.engine.dao.RepairSubscriptionDao;
import com.ning.billing.subscription.engine.dao.SubscriptionDao;
import com.ning.billing.util.config.SubscriptionConfig;
-import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
@@ -68,7 +68,6 @@ public class DefaultSubscriptionModule extends AbstractModule implements Subscri
}
protected void installSubscriptionCore() {
-
bind(SubscriptionBaseApiService.class).annotatedWith(Names.named(REPAIR_NAMED)).to(RepairSubscriptionApiService.class).asEagerSingleton();
bind(SubscriptionBaseApiService.class).to(DefaultSubscriptionBaseApiService.class).asEagerSingleton();
@@ -106,7 +105,6 @@ public class DefaultSubscriptionModule extends AbstractModule implements Subscri
bind(SubscriptionBaseMigrationApi.class).to(DefaultSubscriptionBaseMigrationApi.class).asEagerSingleton();
}
-
@Override
public void installSubscriptionInternalApi() {
bind(SubscriptionBaseInternalApi.class).to(DefaultSubscriptionInternalApi.class).asEagerSingleton();
tenant/pom.xml 2(+1 -1)
diff --git a/tenant/pom.xml b/tenant/pom.xml
index afc66bf..5f070a3 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-tenant</artifactId>
usage/pom.xml 2(+1 -1)
diff --git a/usage/pom.xml b/usage/pom.xml
index f2d5cec..a6de309 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-usage</artifactId>
util/pom.xml 2(+1 -1)
diff --git a/util/pom.xml b/util/pom.xml
index 01c5fba..7ebfe6a 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -12,7 +12,7 @@
<parent>
<artifactId>killbill</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.8.3-SNAPSHOT</version>
+ <version>0.8.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>killbill-util</artifactId>
diff --git a/util/src/main/java/com/ning/billing/util/customfield/ShouldntHappenException.java b/util/src/main/java/com/ning/billing/util/customfield/ShouldntHappenException.java
new file mode 100644
index 0000000..5d4cc2d
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/customfield/ShouldntHappenException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010-2013 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.util.customfield;
+
+public class ShouldntHappenException extends RuntimeException {
+
+ public ShouldntHappenException(final String message) {
+ super(message);
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/mock/glue/MockEntitlementModule.java b/util/src/test/java/com/ning/billing/mock/glue/MockEntitlementModule.java
index 407e98f..60f9fe8 100644
--- a/util/src/test/java/com/ning/billing/mock/glue/MockEntitlementModule.java
+++ b/util/src/test/java/com/ning/billing/mock/glue/MockEntitlementModule.java
@@ -18,6 +18,7 @@ package com.ning.billing.mock.glue;
import org.mockito.Mockito;
+import com.ning.billing.entitlement.EntitlementInternalApi;
import com.ning.billing.entitlement.api.EntitlementApi;
import com.ning.billing.entitlement.api.SubscriptionApi;
import com.ning.billing.glue.EntitlementModule;
@@ -29,6 +30,7 @@ public class MockEntitlementModule extends AbstractModule implements Entitlement
private final BlockingInternalApi blockingApi = Mockito.mock(BlockingInternalApi.class);
private final EntitlementApi entitlementApi = Mockito.mock(EntitlementApi.class);
+ private final EntitlementInternalApi entitlementInternalApi = Mockito.mock(EntitlementInternalApi.class);
private final SubscriptionApi subscriptionApi = Mockito.mock(SubscriptionApi.class);
@Override
@@ -54,6 +56,11 @@ public class MockEntitlementModule extends AbstractModule implements Entitlement
}
@Override
+ public void installEntitlementInternalApi() {
+ bind(EntitlementInternalApi.class).toInstance(entitlementInternalApi);
+ }
+
+ @Override
public void installSubscriptionApi() {
bind(SubscriptionApi.class).toInstance(subscriptionApi);
}
@@ -61,5 +68,4 @@ public class MockEntitlementModule extends AbstractModule implements Entitlement
@Override
public void installBlockingChecker() {
}
-
}