killbill-memoizeit
Changes
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java 158(+10 -148)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java 20(+13 -7)
entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java 296(+296 -0)
Details
diff --git a/api/src/main/java/org/killbill/billing/entitlement/EntitlementInternalApi.java b/api/src/main/java/org/killbill/billing/entitlement/EntitlementInternalApi.java
index 75c4f53..cf812c5 100644
--- a/api/src/main/java/org/killbill/billing/entitlement/EntitlementInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/entitlement/EntitlementInternalApi.java
@@ -18,10 +18,20 @@ package org.killbill.billing.entitlement;
import java.util.UUID;
+import org.joda.time.LocalDate;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.entitlement.api.Entitlement;
import org.killbill.billing.entitlement.api.EntitlementApiException;
-import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.payment.api.PluginProperty;
public interface EntitlementInternalApi {
- public AccountEntitlements getAllEntitlementsForAccountId(UUID accountId, TenantContext context) throws EntitlementApiException;
+ AccountEntitlements getAllEntitlementsForAccountId(UUID accountId, InternalTenantContext context) throws EntitlementApiException;
+
+ Entitlement getEntitlementForId(final UUID uuid, final InternalTenantContext tenantContext) throws EntitlementApiException;
+
+ void pause(UUID bundleId, LocalDate effectiveDate, Iterable<PluginProperty> properties, InternalCallContext context) throws EntitlementApiException;
+
+ void resume(UUID bundleId, LocalDate localEffectiveDate, Iterable<PluginProperty> properties, InternalCallContext context) throws EntitlementApiException;
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
index 6f8f43a..cab5264 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
@@ -16,7 +16,6 @@
package org.killbill.billing.entitlement.api;
-import java.io.IOException;
import java.util.List;
import java.util.UUID;
@@ -26,24 +25,19 @@ import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.account.api.ImmutableAccountData;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.entitlement.AccountEventsStreams;
-import org.killbill.billing.entitlement.DefaultEntitlementService;
import org.killbill.billing.entitlement.EntitlementService;
-import org.killbill.billing.entitlement.EntitlementTransitionType;
import org.killbill.billing.entitlement.EventsStream;
import org.killbill.billing.entitlement.api.EntitlementPluginExecution.WithEntitlementPlugin;
+import org.killbill.billing.entitlement.api.svcs.DefaultEntitlementApiBase;
import org.killbill.billing.entitlement.block.BlockingChecker;
import org.killbill.billing.entitlement.dao.BlockingStateDao;
-import org.killbill.billing.entitlement.engine.core.EntitlementNotificationKey;
-import org.killbill.billing.entitlement.engine.core.EntitlementNotificationKeyAction;
import org.killbill.billing.entitlement.engine.core.EntitlementUtils;
import org.killbill.billing.entitlement.engine.core.EventsStreamBuilder;
import org.killbill.billing.entitlement.plugin.api.EntitlementContext;
@@ -61,12 +55,8 @@ import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.TenantContext;
import org.killbill.bus.api.PersistentBus;
-import org.killbill.bus.api.PersistentBus.EventBusException;
import org.killbill.clock.Clock;
-import org.killbill.notificationq.api.NotificationEvent;
-import org.killbill.notificationq.api.NotificationQueue;
import org.killbill.notificationq.api.NotificationQueueService;
-import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,7 +66,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
-public class DefaultEntitlementApi implements EntitlementApi {
+public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements EntitlementApi {
private static final Logger log = LoggerFactory.getLogger(DefaultEntitlementApi.class);
@@ -99,7 +89,6 @@ public class DefaultEntitlementApi implements EntitlementApi {
private final EntitlementPluginExecution pluginExecution;
private final SecurityApi securityApi;
-
@Inject
public DefaultEntitlementApi(final PersistentBus eventBus, final InternalCallContextFactory internalCallContextFactory,
final SubscriptionBaseTransferApi subscriptionTransferApi, final SubscriptionBaseInternalApi subscriptionInternalApi,
@@ -108,6 +97,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
final EventsStreamBuilder eventsStreamBuilder, final EntitlementUtils entitlementUtils,
final EntitlementPluginExecution pluginExecution,
final SecurityApi securityApi) {
+ super(eventBus, null, pluginExecution, internalCallContextFactory, subscriptionInternalApi, accountApi, blockingStateDao, clock, checker, notificationQueueService, eventsStreamBuilder, entitlementUtils, securityApi);
this.eventBus = eventBus;
this.internalCallContextFactory = internalCallContextFactory;
this.subscriptionBaseInternalApi = subscriptionInternalApi;
@@ -227,11 +217,9 @@ public class DefaultEntitlementApi implements EntitlementApi {
}
@Override
- public Entitlement getEntitlementForId(final UUID uuid, final TenantContext tenantContext) throws EntitlementApiException {
- final EventsStream eventsStream = eventsStreamBuilder.buildForEntitlement(uuid, tenantContext);
- return new DefaultEntitlement(eventsStream, eventsStreamBuilder, this, pluginExecution,
- blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
- entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
+ public Entitlement getEntitlementForId(final UUID entitlementId, final TenantContext tenantContext) throws EntitlementApiException {
+ final InternalTenantContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(entitlementId, ObjectType.SUBSCRIPTION, tenantContext);
+ return super.getEntitlementForId(entitlementId, contextWithValidAccountRecordId);
}
@Override
@@ -286,125 +274,16 @@ public class DefaultEntitlementApi implements EntitlementApi {
@Override
public void pause(final UUID bundleId, final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final CallContext context) throws EntitlementApiException {
- final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.PAUSE_SUBSCRIPTION,
- null,
- null,
- bundleId,
- null,
- null,
- null,
- localEffectiveDate,
- properties,
- context);
-
- final WithEntitlementPlugin<Void> pauseWithPlugin = new WithEntitlementPlugin<Void>() {
- @Override
- public Void doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
- try {
- final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
- final BlockingState currentState = blockingStateDao.getBlockingStateForService(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
- if (currentState != null && currentState.getStateName().equals(ENT_STATE_BLOCKED)) {
- throw new EntitlementApiException(ErrorCode.ENT_ALREADY_BLOCKED, bundleId);
- }
-
- final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getBundleFromId(bundleId, contextWithValidAccountRecordId);
- final ImmutableAccountData account = accountApi.getImmutableAccountDataById(bundle.getAccountId(), contextWithValidAccountRecordId);
- final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
- final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), baseSubscription.getStartDate(), contextWithValidAccountRecordId);
-
- if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, account.getTimeZone())) {
- recordPauseResumeNotificationEntry(baseSubscription.getId(), bundleId, effectiveDate, true, contextWithValidAccountRecordId);
- return null;
- }
-
- final BlockingState state = new DefaultBlockingState(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, ENT_STATE_BLOCKED, EntitlementService.ENTITLEMENT_SERVICE_NAME, true, true, true, effectiveDate);
- entitlementUtils.setBlockingStateAndPostBlockingTransitionEvent(state, contextWithValidAccountRecordId);
-
- // Should we send one event per entitlement in the bundle?
- // Code below only sends one event for the bundle and use the base entitlementId
- final DefaultEffectiveEntitlementEvent event = new DefaultEffectiveEntitlementEvent(state.getId(), baseSubscription.getId(), bundleId, bundle.getAccountId(), EntitlementTransitionType.BLOCK_BUNDLE,
- effectiveDate, clock.getUTCNow(),
- contextWithValidAccountRecordId.getAccountRecordId(), contextWithValidAccountRecordId.getTenantRecordId(),
- contextWithValidAccountRecordId.getUserToken());
-
- try {
- eventBus.post(event);
- } catch (EventBusException e) {
- log.warn("Failed to post bus event for pause operation on bundle " + bundleId);
- }
-
- } catch (SubscriptionBaseApiException e) {
- throw new EntitlementApiException(e);
- } catch (AccountApiException e) {
- throw new EntitlementApiException(e);
- }
- return null;
- }
- };
- pluginExecution.executeWithPlugin(pauseWithPlugin, pluginContext);
+ final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
+ super.pause(bundleId, localEffectiveDate, properties, contextWithValidAccountRecordId);
}
@Override
public void resume(final UUID bundleId, final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final CallContext context) throws EntitlementApiException {
- final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.RESUME_SUBSCRIPTION,
- null,
- null,
- bundleId,
- null,
- null,
- null,
- localEffectiveDate,
- properties,
- context);
- final WithEntitlementPlugin<Void> resumeWithPlugin = new WithEntitlementPlugin<Void>() {
- @Override
- public Void doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
- try {
- final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
- final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getBundleFromId(bundleId, contextWithValidAccountRecordId);
- final ImmutableAccountData account = accountApi.getImmutableAccountDataById(bundle.getAccountId(), contextWithValidAccountRecordId);
- final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
-
- final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), baseSubscription.getStartDate(), contextWithValidAccountRecordId);
-
- if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, account.getTimeZone())) {
- recordPauseResumeNotificationEntry(baseSubscription.getId(), bundleId, effectiveDate, false, contextWithValidAccountRecordId);
- return null;
- }
-
- final BlockingState currentState = blockingStateDao.getBlockingStateForService(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
- if (currentState == null || currentState.getStateName().equals(ENT_STATE_CLEAR)) {
- // Nothing to do.
- log.warn("Current state is {}, nothing to resume", currentState);
- return null;
- }
-
- final BlockingState state = new DefaultBlockingState(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, ENT_STATE_CLEAR, EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, effectiveDate);
- entitlementUtils.setBlockingStateAndPostBlockingTransitionEvent(state, contextWithValidAccountRecordId);
+ final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
+ super.resume(bundleId, localEffectiveDate, properties, contextWithValidAccountRecordId);
- // Should we send one event per entitlement in the bundle?
- // Code below only sends one event for the bundle and use the base entitlementId
- final DefaultEffectiveEntitlementEvent event = new DefaultEffectiveEntitlementEvent(state.getId(), baseSubscription.getId(), bundleId, bundle.getAccountId(), EntitlementTransitionType.UNBLOCK_BUNDLE,
- effectiveDate, clock.getUTCNow(),
- contextWithValidAccountRecordId.getAccountRecordId(), contextWithValidAccountRecordId.getTenantRecordId(),
- contextWithValidAccountRecordId.getUserToken());
-
- try {
- eventBus.post(event);
- } catch (EventBusException e) {
- log.warn("Failed to post bus event for resume operation on bundle " + bundleId);
- }
-
- } catch (SubscriptionBaseApiException e) {
- throw new EntitlementApiException(e);
- } catch (AccountApiException e) {
- throw new EntitlementApiException(e);
- }
- return null;
- }
- };
- pluginExecution.executeWithPlugin(resumeWithPlugin, pluginContext);
}
@Override
@@ -474,21 +353,4 @@ public class DefaultEntitlementApi implements EntitlementApi {
};
return pluginExecution.executeWithPlugin(transferWithPlugin, pluginContext);
}
-
- private void recordPauseResumeNotificationEntry(final UUID entitlementId, final UUID bundleId, final DateTime effectiveDate, final boolean isPause, final InternalCallContext contextWithValidAccountRecordId) throws EntitlementApiException {
- final NotificationEvent notificationEvent = new EntitlementNotificationKey(entitlementId,
- bundleId,
- isPause ? EntitlementNotificationKeyAction.PAUSE : EntitlementNotificationKeyAction.RESUME,
- effectiveDate);
-
- try {
- final NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
- DefaultEntitlementService.NOTIFICATION_QUEUE_NAME);
- subscriptionEventQueue.recordFutureNotification(effectiveDate, notificationEvent, contextWithValidAccountRecordId.getUserToken(), contextWithValidAccountRecordId.getAccountRecordId(), contextWithValidAccountRecordId.getTenantRecordId());
- } catch (final NoSuchNotificationQueue e) {
- throw new EntitlementApiException(e, ErrorCode.__UNKNOWN_ERROR_CODE);
- } catch (final IOException e) {
- throw new EntitlementApiException(e, ErrorCode.__UNKNOWN_ERROR_CODE);
- }
- }
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
index 8da4329..5aeffe1 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -95,13 +95,14 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
}
@Override
- public Subscription getSubscriptionForEntitlementId(final UUID entitlementId, final TenantContext context) throws SubscriptionApiException {
- final UUID accountId = internalCallContextFactory.getAccountId(entitlementId, ObjectType.SUBSCRIPTION, context);
+ public Subscription getSubscriptionForEntitlementId(final UUID entitlementId, final TenantContext tenantContext) throws SubscriptionApiException {
// Retrieve entitlements
final AccountEntitlements accountEntitlements;
try {
- accountEntitlements = entitlementInternalApi.getAllEntitlementsForAccountId(accountId, context);
+ final UUID accountId = internalCallContextFactory.getAccountId(entitlementId, ObjectType.SUBSCRIPTION, tenantContext);
+ final InternalTenantContext internalTenantContextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(accountId, tenantContext);
+ accountEntitlements = entitlementInternalApi.getAllEntitlementsForAccountId(accountId, internalTenantContextWithValidAccountRecordId);
} catch (final EntitlementApiException e) {
throw new SubscriptionApiException(e);
}
@@ -119,10 +120,14 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
}
@Override
- public SubscriptionBundle getSubscriptionBundle(final UUID bundleId, final TenantContext context) throws SubscriptionApiException {
- final UUID accountId = internalCallContextFactory.getAccountId(bundleId, ObjectType.BUNDLE, context);
+ public SubscriptionBundle getSubscriptionBundle(final UUID bundleId, final TenantContext tenantContext) throws SubscriptionApiException {
- final Optional<SubscriptionBundle> bundleOptional = Iterables.<SubscriptionBundle>tryFind(getSubscriptionBundlesForAccount(accountId, context),
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantContext);
+
+
+ final UUID accountId = internalCallContextFactory.getAccountId(bundleId, ObjectType.BUNDLE, tenantContext);
+
+ final Optional<SubscriptionBundle> bundleOptional = Iterables.<SubscriptionBundle>tryFind(getSubscriptionBundlesForAccount(accountId, tenantContext),
new Predicate<SubscriptionBundle>() {
@Override
public boolean apply(final SubscriptionBundle bundle) {
@@ -239,7 +244,8 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
// Retrieve entitlements
final AccountEntitlements accountEntitlements;
try {
- accountEntitlements = entitlementInternalApi.getAllEntitlementsForAccountId(accountId, tenantContext);
+ final InternalTenantContext internalTenantContextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(accountId, tenantContext);
+ accountEntitlements = entitlementInternalApi.getAllEntitlementsForAccountId(accountId, internalTenantContextWithValidAccountRecordId);
} catch (final EntitlementApiException e) {
throw new SubscriptionApiException(e);
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java
new file mode 100644
index 0000000..56ce01c
--- /dev/null
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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 org.killbill.billing.entitlement.api.svcs;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.killbill.billing.ErrorCode;
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.entitlement.AccountEntitlements;
+import org.killbill.billing.entitlement.AccountEventsStreams;
+import org.killbill.billing.entitlement.DefaultEntitlementService;
+import org.killbill.billing.entitlement.EntitlementInternalApi;
+import org.killbill.billing.entitlement.EntitlementService;
+import org.killbill.billing.entitlement.EntitlementTransitionType;
+import org.killbill.billing.entitlement.EventsStream;
+import org.killbill.billing.entitlement.api.BlockingState;
+import org.killbill.billing.entitlement.api.BlockingStateType;
+import org.killbill.billing.entitlement.api.DefaultEffectiveEntitlementEvent;
+import org.killbill.billing.entitlement.api.DefaultEntitlement;
+import org.killbill.billing.entitlement.api.DefaultEntitlementApi;
+import org.killbill.billing.entitlement.api.DefaultEntitlementContext;
+import org.killbill.billing.entitlement.api.Entitlement;
+import org.killbill.billing.entitlement.api.EntitlementApi;
+import org.killbill.billing.entitlement.api.EntitlementApiException;
+import org.killbill.billing.entitlement.api.EntitlementDateHelper;
+import org.killbill.billing.entitlement.api.EntitlementPluginExecution;
+import org.killbill.billing.entitlement.api.EntitlementPluginExecution.WithEntitlementPlugin;
+import org.killbill.billing.entitlement.block.BlockingChecker;
+import org.killbill.billing.entitlement.dao.BlockingStateDao;
+import org.killbill.billing.entitlement.engine.core.EntitlementNotificationKey;
+import org.killbill.billing.entitlement.engine.core.EntitlementNotificationKeyAction;
+import org.killbill.billing.entitlement.engine.core.EntitlementUtils;
+import org.killbill.billing.entitlement.engine.core.EventsStreamBuilder;
+import org.killbill.billing.entitlement.plugin.api.EntitlementContext;
+import org.killbill.billing.entitlement.plugin.api.OperationType;
+import org.killbill.billing.junction.DefaultBlockingState;
+import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.security.api.SecurityApi;
+import org.killbill.billing.subscription.api.SubscriptionBase;
+import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.bus.api.PersistentBus;
+import org.killbill.bus.api.PersistentBus.EventBusException;
+import org.killbill.clock.Clock;
+import org.killbill.notificationq.api.NotificationEvent;
+import org.killbill.notificationq.api.NotificationQueue;
+import org.killbill.notificationq.api.NotificationQueueService;
+import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultEntitlementApiBase {
+
+ private static final Logger log = LoggerFactory.getLogger(DefaultEntitlementApiBase.class);
+
+
+ protected final EntitlementApi entitlementApi;
+ protected final AccountInternalApi accountApi;
+
+ protected final SubscriptionBaseInternalApi subscriptionInternalApi;
+ protected final Clock clock;
+ protected final InternalCallContextFactory internalCallContextFactory;
+ protected final BlockingChecker checker;
+ protected final BlockingStateDao blockingStateDao;
+ protected final EntitlementDateHelper dateHelper;
+ protected final EventsStreamBuilder eventsStreamBuilder;
+ protected final EntitlementUtils entitlementUtils;
+ protected final NotificationQueueService notificationQueueService;
+ protected final EntitlementPluginExecution pluginExecution;
+ protected final SecurityApi securityApi;
+ protected final PersistentBus eventBus;
+
+ protected DefaultEntitlementApiBase(final PersistentBus eventBus,
+ @Nullable final EntitlementApi entitlementApi, final EntitlementPluginExecution pluginExecution,
+ 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, final SecurityApi securityApi) {
+ this.eventBus = eventBus;
+ this.entitlementApi = entitlementApi != null ? entitlementApi : (EntitlementApi) this;
+ this.accountApi = accountApi;
+ this.pluginExecution= pluginExecution;
+ 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.securityApi = securityApi;
+ this.dateHelper = new EntitlementDateHelper(accountApi, clock);
+ }
+
+ public AccountEntitlements getAllEntitlementsForAccountId(final UUID accountId, final InternalTenantContext tenantContext) throws EntitlementApiException {
+
+ final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(tenantContext);
+
+ 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, pluginExecution,
+ blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
+ entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
+ entitlementsPerBundle.get(bundleId).add(entitlement);
+ }
+ }
+
+ return new DefaultAccountEntitlements(accountEventsStreams, entitlementsPerBundle);
+ }
+
+ public Entitlement getEntitlementForId(final UUID entitlementId, final InternalTenantContext tenantContext) throws EntitlementApiException {
+ final EventsStream eventsStream = eventsStreamBuilder.buildForEntitlement(entitlementId, tenantContext);
+ return new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi, pluginExecution,
+ blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
+ entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
+ }
+
+ public void pause(final UUID bundleId, final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
+
+ final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.PAUSE_SUBSCRIPTION,
+ null,
+ null,
+ bundleId,
+ null,
+ null,
+ null,
+ localEffectiveDate,
+ properties,
+ internalCallContextFactory.createCallContext(internalCallContext));
+
+ final WithEntitlementPlugin<Void> pauseWithPlugin = new WithEntitlementPlugin<Void>() {
+ @Override
+ public Void doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
+ try {
+
+ final BlockingState currentState = blockingStateDao.getBlockingStateForService(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, EntitlementService.ENTITLEMENT_SERVICE_NAME, internalCallContext);
+ if (currentState != null && currentState.getStateName().equals(DefaultEntitlementApi.ENT_STATE_BLOCKED)) {
+ throw new EntitlementApiException(ErrorCode.ENT_ALREADY_BLOCKED, bundleId);
+ }
+
+ final SubscriptionBaseBundle bundle = subscriptionInternalApi.getBundleFromId(bundleId, internalCallContext);
+ final ImmutableAccountData account = accountApi.getImmutableAccountDataById(bundle.getAccountId(), internalCallContext);
+ final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, internalCallContext);
+ final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), baseSubscription.getStartDate(), internalCallContext);
+
+ if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, account.getTimeZone())) {
+ recordPauseResumeNotificationEntry(baseSubscription.getId(), bundleId, effectiveDate, true, internalCallContext);
+ return null;
+ }
+
+ final BlockingState state = new DefaultBlockingState(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, DefaultEntitlementApi.ENT_STATE_BLOCKED, EntitlementService.ENTITLEMENT_SERVICE_NAME, true, true, true, effectiveDate);
+ entitlementUtils.setBlockingStateAndPostBlockingTransitionEvent(state, internalCallContext);
+
+ // Should we send one event per entitlement in the bundle?
+ // Code below only sends one event for the bundle and use the base entitlementId
+ final DefaultEffectiveEntitlementEvent event = new DefaultEffectiveEntitlementEvent(state.getId(), baseSubscription.getId(), bundleId, bundle.getAccountId(), EntitlementTransitionType.BLOCK_BUNDLE,
+ effectiveDate, clock.getUTCNow(),
+ internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId(),
+ internalCallContext.getUserToken());
+
+ try {
+ eventBus.post(event);
+ } catch (EventBusException e) {
+ log.warn("Failed to post bus event for pause operation on bundle " + bundleId);
+ }
+
+ } catch (SubscriptionBaseApiException e) {
+ throw new EntitlementApiException(e);
+ } catch (AccountApiException e) {
+ throw new EntitlementApiException(e);
+ }
+ return null;
+ }
+ };
+ pluginExecution.executeWithPlugin(pauseWithPlugin, pluginContext);
+ }
+
+ public void resume(final UUID bundleId, final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
+
+ final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.RESUME_SUBSCRIPTION,
+ null,
+ null,
+ bundleId,
+ null,
+ null,
+ null,
+ localEffectiveDate,
+ properties,
+ internalCallContextFactory.createCallContext(internalCallContext));
+ final WithEntitlementPlugin<Void> resumeWithPlugin = new WithEntitlementPlugin<Void>() {
+ @Override
+ public Void doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
+ try {
+ final SubscriptionBaseBundle bundle = subscriptionInternalApi.getBundleFromId(bundleId, internalCallContext);
+ final ImmutableAccountData account = accountApi.getImmutableAccountDataById(bundle.getAccountId(), internalCallContext);
+ final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, internalCallContext);
+
+ final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), baseSubscription.getStartDate(), internalCallContext);
+
+ if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, account.getTimeZone())) {
+ recordPauseResumeNotificationEntry(baseSubscription.getId(), bundleId, effectiveDate, false, internalCallContext);
+ return null;
+ }
+
+ final BlockingState currentState = blockingStateDao.getBlockingStateForService(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, EntitlementService.ENTITLEMENT_SERVICE_NAME, internalCallContext);
+ if (currentState == null || currentState.getStateName().equals(DefaultEntitlementApi.ENT_STATE_CLEAR)) {
+ // Nothing to do.
+ log.warn("Current state is {}, nothing to resume", currentState);
+ return null;
+ }
+
+ final BlockingState state = new DefaultBlockingState(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, DefaultEntitlementApi.ENT_STATE_CLEAR, EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, effectiveDate);
+ entitlementUtils.setBlockingStateAndPostBlockingTransitionEvent(state, internalCallContext);
+
+ // Should we send one event per entitlement in the bundle?
+ // Code below only sends one event for the bundle and use the base entitlementId
+ final DefaultEffectiveEntitlementEvent event = new DefaultEffectiveEntitlementEvent(state.getId(), baseSubscription.getId(), bundleId, bundle.getAccountId(), EntitlementTransitionType.UNBLOCK_BUNDLE,
+ effectiveDate, clock.getUTCNow(),
+ internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId(),
+ internalCallContext.getUserToken());
+
+ try {
+ eventBus.post(event);
+ } catch (EventBusException e) {
+ log.warn("Failed to post bus event for resume operation on bundle " + bundleId);
+ }
+
+ } catch (SubscriptionBaseApiException e) {
+ throw new EntitlementApiException(e);
+ } catch (AccountApiException e) {
+ throw new EntitlementApiException(e);
+ }
+ return null;
+ }
+ };
+ pluginExecution.executeWithPlugin(resumeWithPlugin, pluginContext);
+ }
+
+
+ protected void recordPauseResumeNotificationEntry(final UUID entitlementId, final UUID bundleId, final DateTime effectiveDate, final boolean isPause, final InternalCallContext contextWithValidAccountRecordId) throws EntitlementApiException {
+ final NotificationEvent notificationEvent = new EntitlementNotificationKey(entitlementId,
+ bundleId,
+ isPause ? EntitlementNotificationKeyAction.PAUSE : EntitlementNotificationKeyAction.RESUME,
+ effectiveDate);
+
+ try {
+ final NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
+ DefaultEntitlementService.NOTIFICATION_QUEUE_NAME);
+ subscriptionEventQueue.recordFutureNotification(effectiveDate, notificationEvent, contextWithValidAccountRecordId.getUserToken(), contextWithValidAccountRecordId.getAccountRecordId(), contextWithValidAccountRecordId.getTenantRecordId());
+ } catch (final NoSuchNotificationQueue e) {
+ throw new EntitlementApiException(e, ErrorCode.__UNKNOWN_ERROR_CODE);
+ } catch (final IOException e) {
+ throw new EntitlementApiException(e, ErrorCode.__UNKNOWN_ERROR_CODE);
+ }
+ }
+
+}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
index b9fb7af..52e03f4 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
@@ -16,93 +16,34 @@
package org.killbill.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 org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.entitlement.api.EntitlementPluginExecution;
-import org.killbill.billing.security.api.SecurityApi;
-import org.killbill.clock.Clock;
-import org.killbill.billing.entitlement.AccountEntitlements;
-import org.killbill.billing.entitlement.AccountEventsStreams;
import org.killbill.billing.entitlement.EntitlementInternalApi;
-import org.killbill.billing.entitlement.EventsStream;
-import org.killbill.billing.entitlement.api.DefaultEntitlement;
-import org.killbill.billing.entitlement.api.Entitlement;
import org.killbill.billing.entitlement.api.EntitlementApi;
-import org.killbill.billing.entitlement.api.EntitlementApiException;
-import org.killbill.billing.entitlement.api.EntitlementDateHelper;
+import org.killbill.billing.entitlement.api.EntitlementPluginExecution;
import org.killbill.billing.entitlement.block.BlockingChecker;
import org.killbill.billing.entitlement.dao.BlockingStateDao;
import org.killbill.billing.entitlement.engine.core.EntitlementUtils;
import org.killbill.billing.entitlement.engine.core.EventsStreamBuilder;
-import org.killbill.notificationq.api.NotificationQueueService;
+import org.killbill.billing.security.api.SecurityApi;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.callcontext.TenantContext;
-
-public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
+import org.killbill.bus.api.PersistentBus;
+import org.killbill.clock.Clock;
+import org.killbill.notificationq.api.NotificationQueueService;
- 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;
- private final EntitlementPluginExecution pluginExecution;
- private final SecurityApi securityApi;
+public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase implements EntitlementInternalApi {
@Inject
- public DefaultEntitlementInternalApi(final EntitlementApi entitlementApi, final EntitlementPluginExecution pluginExecution,
+ public DefaultEntitlementInternalApi(final PersistentBus eventBus,
+ final EntitlementApi entitlementApi, final EntitlementPluginExecution pluginExecution,
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, final SecurityApi securityApi) {
- this.entitlementApi = entitlementApi;
- this.pluginExecution= pluginExecution;
- 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.securityApi = securityApi;
- this.dateHelper = new EntitlementDateHelper(accountApi, clock);
+ super(eventBus, entitlementApi, pluginExecution, internalCallContextFactory, subscriptionInternalApi, accountApi, blockingStateDao, clock, checker, notificationQueueService, eventsStreamBuilder, entitlementUtils, securityApi);
}
- @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, pluginExecution,
- blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
- entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
- entitlementsPerBundle.get(bundleId).add(entitlement);
- }
- }
-
- return new DefaultAccountEntitlements(accountEventsStreams, entitlementsPerBundle);
- }
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java b/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
index d93e058..f62b795 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
@@ -25,7 +25,6 @@ import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.entitlement.api.DefaultBlockingTransitionInternalEvent;
import org.killbill.billing.entitlement.api.DefaultEntitlement;
import org.killbill.billing.entitlement.api.Entitlement;
-import org.killbill.billing.entitlement.api.EntitlementApi;
import org.killbill.billing.entitlement.api.EntitlementApiException;
import org.killbill.billing.entitlement.dao.BlockingStateDao;
import org.killbill.billing.entitlement.engine.core.BlockingTransitionNotificationKey;
@@ -59,7 +58,7 @@ public class DefaultEntitlementService implements EntitlementService {
private static final Logger log = LoggerFactory.getLogger(DefaultEntitlementService.class);
- private final EntitlementApi entitlementApi;
+ private final EntitlementInternalApi entitlementInternalApi;
private final BlockingStateDao blockingStateDao;
private final PersistentBus eventBus;
private final NotificationQueueService notificationQueueService;
@@ -68,12 +67,12 @@ public class DefaultEntitlementService implements EntitlementService {
private NotificationQueue entitlementEventQueue;
@Inject
- public DefaultEntitlementService(final EntitlementApi entitlementApi,
+ public DefaultEntitlementService(final EntitlementInternalApi entitlementInternalApi,
final BlockingStateDao blockingStateDao,
final PersistentBus eventBus,
final NotificationQueueService notificationQueueService,
final InternalCallContextFactory internalCallContextFactory) {
- this.entitlementApi = entitlementApi;
+ this.entitlementInternalApi = entitlementInternalApi;
this.blockingStateDao = blockingStateDao;
this.eventBus = eventBus;
this.notificationQueueService = notificationQueueService;
@@ -117,7 +116,7 @@ public class DefaultEntitlementService implements EntitlementService {
private void processEntitlementNotification(final EntitlementNotificationKey key, final InternalCallContext internalCallContext, final CallContext callContext) {
final Entitlement entitlement;
try {
- entitlement = entitlementApi.getEntitlementForId(key.getEntitlementId(), callContext);
+ entitlement = entitlementInternalApi.getEntitlementForId(key.getEntitlementId(), internalCallContext);
} catch (final EntitlementApiException e) {
log.error("Error retrieving entitlement for id " + key.getEntitlementId(), e);
return;
@@ -134,9 +133,9 @@ public class DefaultEntitlementService implements EntitlementService {
EntitlementNotificationKeyAction.CANCEL.equals(entitlementNotificationKeyAction)) {
((DefaultEntitlement) entitlement).blockAddOnsIfRequired(key.getEffectiveDate(), callContext, internalCallContext);
} else if (EntitlementNotificationKeyAction.PAUSE.equals(entitlementNotificationKeyAction)) {
- entitlementApi.pause(key.getBundleId(), key.getEffectiveDate().toLocalDate(), ImmutableList.<PluginProperty>of(), callContext);
+ entitlementInternalApi.pause(key.getBundleId(), key.getEffectiveDate().toLocalDate(), ImmutableList.<PluginProperty>of(), internalCallContext);
} else if (EntitlementNotificationKeyAction.RESUME.equals(entitlementNotificationKeyAction)) {
- entitlementApi.resume(key.getBundleId(), key.getEffectiveDate().toLocalDate(), ImmutableList.<PluginProperty>of(), callContext);
+ entitlementInternalApi.resume(key.getBundleId(), key.getEffectiveDate().toLocalDate(), ImmutableList.<PluginProperty>of(), internalCallContext);
}
} catch (final EntitlementApiException e) {
log.error("Error processing event for entitlement {}" + entitlement.getId(), e);