killbill-memoizeit
Changes
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/IntegrationTestOverdueModule.java 4(+0 -4)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/MockOverdueService.java 46(+0 -46)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java 4(+1 -3)
overdue/src/main/java/org/killbill/billing/overdue/caching/EhCacheOverdueConfigCache.java 123(+123 -0)
overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java 1(+0 -1)
util/src/main/resources/ehcache.xml 13(+13 -0)
Details
diff --git a/api/src/main/java/org/killbill/billing/glue/OverdueModule.java b/api/src/main/java/org/killbill/billing/glue/OverdueModule.java
index 7dc786b..c10b111 100644
--- a/api/src/main/java/org/killbill/billing/glue/OverdueModule.java
+++ b/api/src/main/java/org/killbill/billing/glue/OverdueModule.java
@@ -18,6 +18,6 @@ package org.killbill.billing.glue;
public interface OverdueModule {
- public abstract void installOverdueUserApi();
+ public void installOverdueUserApi();
}
diff --git a/api/src/main/java/org/killbill/billing/overdue/OverdueService.java b/api/src/main/java/org/killbill/billing/overdue/OverdueService.java
index 59bec21..88b7af0 100644
--- a/api/src/main/java/org/killbill/billing/overdue/OverdueService.java
+++ b/api/src/main/java/org/killbill/billing/overdue/OverdueService.java
@@ -18,13 +18,14 @@
package org.killbill.billing.overdue;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.overdue.api.OverdueApiException;
+import org.killbill.billing.overdue.api.OverdueConfig;
import org.killbill.billing.platform.api.KillbillService;
public interface OverdueService extends KillbillService {
- String OVERDUE_SERVICE_NAME = "overdue-service";
+ public static final String OVERDUE_SERVICE_NAME = "overdue-service";
- public String getName();
-
- public OverdueInternalApi getUserApi();
+ public OverdueConfig getOverdueConfig(final InternalTenantContext internalTenantContext) throws OverdueApiException;
}
diff --git a/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java b/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java
index 2b7aee0..c1ff94a 100644
--- a/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java
@@ -22,5 +22,7 @@ import java.util.List;
import org.killbill.billing.callcontext.InternalTenantContext;
public interface TenantInternalApi {
- List<String> getTenantCatalogs(InternalTenantContext tenantContext);
+ public List<String> getTenantCatalogs(InternalTenantContext tenantContext);
+
+ public String getTenantOverdueConfig(InternalTenantContext tenantContext);
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/IntegrationTestOverdueModule.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/IntegrationTestOverdueModule.java
index edee13b..510fcd2 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/IntegrationTestOverdueModule.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/IntegrationTestOverdueModule.java
@@ -18,7 +18,6 @@
package org.killbill.billing.beatrix.integration.overdue;
-import org.killbill.billing.overdue.OverdueService;
import org.killbill.billing.overdue.glue.DefaultOverdueModule;
import org.killbill.billing.platform.api.KillbillConfigSource;
@@ -28,7 +27,4 @@ public class IntegrationTestOverdueModule extends DefaultOverdueModule {
super(configSource);
}
- protected void installOverdueService() {
- bind(OverdueService.class).to(MockOverdueService.class);
- }
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java
index c9d3f15..ccc25d5 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java
@@ -60,9 +60,7 @@ public abstract class TestOverdueBase extends TestIntegrationBase {
final String configXml = getOverdueConfig();
final InputStream is = new ByteArrayInputStream(configXml.getBytes());
final DefaultOverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class);
- overdueWrapperFactory.setOverdueConfig(config);
- overdueListener.setOverdueConfig(config);
- ((DefaultOverdueInternalApi) overdueUserApi).setOverdueConfig(config);
+ overdueConfigCache.loadDefaultOverdueConfig(config);
account = createAccountWithNonOsgiPaymentMethod(getAccountData(0));
assertNotNull(account);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 8eb8204..ee1d9be 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -72,6 +72,8 @@ import org.killbill.billing.lifecycle.glue.BusModule;
import org.killbill.billing.mock.MockAccountBuilder;
import org.killbill.billing.osgi.config.OSGIConfig;
import org.killbill.billing.overdue.OverdueInternalApi;
+import org.killbill.billing.overdue.api.OverdueConfig;
+import org.killbill.billing.overdue.caching.OverdueConfigCache;
import org.killbill.billing.overdue.listener.OverdueListener;
import org.killbill.billing.overdue.wrapper.OverdueWrapperFactory;
import org.killbill.billing.payment.api.Payment;
@@ -247,6 +249,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
@Inject
protected TestApiListener busHandler;
+ @Inject
+ protected OverdueConfigCache overdueConfigCache;
+
protected void assertListenerStatus() {
busHandler.assertListenerStatus();
}
@@ -268,6 +273,8 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
controlCacheDispatcher.clearAll();
+ overdueConfigCache.loadDefaultOverdueConfig((OverdueConfig) null);
+
clock.resetDeltaFromReality();
busHandler.reset();
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java b/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
index 63bc812..b5e0d13 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
@@ -15,18 +15,18 @@
*/
package org.killbill.billing.overdue.api;
-import org.killbill.billing.overdue.OverdueInternalApi;
-import org.killbill.billing.overdue.config.DefaultOverdueConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.entitlement.api.BlockingStateType;
import org.killbill.billing.junction.BlockingInternalApi;
+import org.killbill.billing.overdue.OverdueInternalApi;
import org.killbill.billing.overdue.OverdueService;
+import org.killbill.billing.overdue.caching.OverdueConfigCache;
+import org.killbill.billing.overdue.config.DefaultOverdueConfig;
import org.killbill.billing.overdue.config.api.BillingState;
import org.killbill.billing.overdue.config.api.OverdueException;
import org.killbill.billing.overdue.config.api.OverdueStateSet;
@@ -35,6 +35,8 @@ import org.killbill.billing.overdue.wrapper.OverdueWrapperFactory;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.TenantContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
@@ -45,13 +47,16 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
private final OverdueWrapperFactory factory;
private final BlockingInternalApi accessApi;
private final InternalCallContextFactory internalCallContextFactory;
-
- private DefaultOverdueConfig overdueConfig;
+ private final OverdueConfigCache overdueConfigCache;
@Inject
- public DefaultOverdueInternalApi(final OverdueWrapperFactory factory, final BlockingInternalApi accessApi, final InternalCallContextFactory internalCallContextFactory) {
+ public DefaultOverdueInternalApi(final OverdueWrapperFactory factory,
+ final BlockingInternalApi accessApi,
+ final OverdueConfigCache overdueConfigCache,
+ final InternalCallContextFactory internalCallContextFactory) {
this.factory = factory;
this.accessApi = accessApi;
+ this.overdueConfigCache = overdueConfigCache;
this.internalCallContextFactory = internalCallContextFactory;
}
@@ -59,8 +64,10 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
@Override
public OverdueState getOverdueStateFor(final Account overdueable, final TenantContext context) throws OverdueException {
try {
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
final String stateName = accessApi.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, internalCallContextFactory.createInternalTenantContext(context)).getStateName();
- final OverdueStateSet states = overdueConfig.getOverdueStatesAccount();
+ final OverdueConfig overdueConfig = overdueConfigCache.getOverdueConfig(internalTenantContext);
+ final OverdueStateSet states = ((DefaultOverdueConfig) overdueConfig).getOverdueStatesAccount();
return states.findState(stateName);
} catch (OverdueApiException e) {
throw new OverdueException(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, overdueable.getId(), overdueable.getClass().getSimpleName());
@@ -70,15 +77,18 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
@Override
public BillingState getBillingStateFor(final Account overdueable, final TenantContext context) throws OverdueException {
log.debug("Billing state of of {} requested", overdueable.getId());
- final OverdueWrapper wrapper = factory.createOverdueWrapperFor(overdueable);
- return wrapper.billingState(internalCallContextFactory.createInternalTenantContext(context));
+
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
+ final OverdueWrapper wrapper = factory.createOverdueWrapperFor(overdueable, internalTenantContext);
+ return wrapper.billingState(internalTenantContext);
}
@Override
public OverdueState refreshOverdueStateFor(final Account blockable, final CallContext context) throws OverdueException, OverdueApiException {
log.info("Refresh of blockable {} ({}) requested", blockable.getId(), blockable.getClass());
- final OverdueWrapper wrapper = factory.createOverdueWrapperFor(blockable);
- return wrapper.refresh(createInternalCallContext(blockable, context));
+ final InternalCallContext internalCallContext = createInternalCallContext(blockable, context);
+ final OverdueWrapper wrapper = factory.createOverdueWrapperFor(blockable, internalCallContext);
+ return wrapper.refresh(internalCallContext);
}
private InternalCallContext createInternalCallContext(final Account blockable, final CallContext context) {
@@ -89,8 +99,4 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
public void setOverrideBillingStateForAccount(final Account overdueable, final BillingState state, final CallContext context) {
throw new UnsupportedOperationException();
}
-
- public void setOverdueConfig(final DefaultOverdueConfig config) {
- this.overdueConfig = config;
- }
}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/caching/EhCacheOverdueConfigCache.java b/overdue/src/main/java/org/killbill/billing/overdue/caching/EhCacheOverdueConfigCache.java
new file mode 100644
index 0000000..8a15187
--- /dev/null
+++ b/overdue/src/main/java/org/killbill/billing/overdue/caching/EhCacheOverdueConfigCache.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.overdue.caching;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URI;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+
+import org.killbill.billing.ErrorCode;
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.overdue.api.OverdueApiException;
+import org.killbill.billing.overdue.api.OverdueConfig;
+import org.killbill.billing.overdue.config.DefaultOverdueConfig;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheController;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.cache.CacheLoaderArgument;
+import org.killbill.billing.util.cache.TenantOverdueConfigCacheLoader.LoaderCallback;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.xmlloader.XMLLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EhCacheOverdueConfigCache implements OverdueConfigCache {
+
+ private static final Logger log = LoggerFactory.getLogger(EhCacheOverdueConfigCache.class);
+
+ private OverdueConfig defaultOverdueConfig;
+
+ private final CacheController cacheController;
+ private final CacheLoaderArgument cacheLoaderArgument;
+
+ @Inject
+ public EhCacheOverdueConfigCache(final CacheControllerDispatcher cacheControllerDispatcher) {
+ this.cacheController = cacheControllerDispatcher.getCacheController(CacheType.TENANT_OVERDUE_CONFIG);
+ this.cacheLoaderArgument = initializeCacheLoaderArgument();
+ }
+
+ @Override
+ public void loadDefaultOverdueConfig(@Nullable final String configURI) throws OverdueApiException {
+ boolean missingOrCorruptedDefaultConfig;
+ try {
+ if (configURI == null || configURI.isEmpty()) {
+ missingOrCorruptedDefaultConfig = true;
+ } else {
+ final URI u = new URI(configURI);
+ defaultOverdueConfig = XMLLoader.getObjectFromUri(u, DefaultOverdueConfig.class);
+ missingOrCorruptedDefaultConfig = (defaultOverdueConfig == null);
+ }
+ } catch (Exception e) {
+ missingOrCorruptedDefaultConfig = true;
+ log.warn("Exception loading default overdue config from " + configURI, e);
+ }
+ if (missingOrCorruptedDefaultConfig) {
+ defaultOverdueConfig = new DefaultOverdueConfig();
+ log.warn("Overdue system disabled: unable to load the overdue config from " + configURI);
+ }
+ }
+
+ @Override
+ public void loadDefaultOverdueConfig(final OverdueConfig config) throws OverdueApiException {
+ defaultOverdueConfig = config;
+ }
+
+ @Override
+ public OverdueConfig getOverdueConfig(final InternalTenantContext tenantContext) throws OverdueApiException {
+
+ if (tenantContext.getTenantRecordId() == InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID) {
+ return defaultOverdueConfig;
+ }
+ // The cache loader might choke on some bad xml -- unlikely since we check its validity prior storing it,
+ // but to be on the safe side;;
+ try {
+ final OverdueConfig overdueConfig = (OverdueConfig) cacheController.get(tenantContext, cacheLoaderArgument);
+ return (overdueConfig != null) ? overdueConfig : defaultOverdueConfig;
+ } catch (IllegalStateException e) {
+ throw new OverdueApiException(ErrorCode.OVERDUE_INVALID_FOR_TENANT, tenantContext.getTenantRecordId());
+ }
+ }
+
+ private CacheLoaderArgument initializeCacheLoaderArgument() {
+ final LoaderCallback loaderCallback = new LoaderCallback() {
+ @Override
+ public Object loadCatalog(final String catalogXMLs) throws OverdueApiException {
+ final InputStream overdueConfigStream = new ByteArrayInputStream(catalogXMLs.getBytes());
+ final URI uri;
+ try {
+ uri = new URI("/overdueConfig");
+ final DefaultOverdueConfig overdueConfig = XMLLoader.getObjectFromStream(uri, overdueConfigStream, DefaultOverdueConfig.class);
+ return overdueConfig;
+ } catch (Exception e) {
+ throw new OverdueApiException(ErrorCode.OVERDUE_INVALID_FOR_TENANT, "Problem encountered loading overdue config ", e);
+ }
+ }
+ };
+ final Object[] args = new Object[1];
+ args[0] = loaderCallback;
+ final ObjectType irrelevant = null;
+ final InternalTenantContext notUsed = null;
+ return new CacheLoaderArgument(irrelevant, args, notUsed);
+ }
+
+}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/caching/OverdueConfigCache.java b/overdue/src/main/java/org/killbill/billing/overdue/caching/OverdueConfigCache.java
new file mode 100644
index 0000000..0e1a65e
--- /dev/null
+++ b/overdue/src/main/java/org/killbill/billing/overdue/caching/OverdueConfigCache.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.overdue.caching;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.overdue.api.OverdueApiException;
+import org.killbill.billing.overdue.api.OverdueConfig;
+
+public interface OverdueConfigCache {
+
+ public void loadDefaultOverdueConfig(String url) throws OverdueApiException;
+
+ public void loadDefaultOverdueConfig(OverdueConfig config) throws OverdueApiException;
+
+ public OverdueConfig getOverdueConfig(InternalTenantContext tenantContext) throws OverdueApiException;
+}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/glue/DefaultOverdueModule.java b/overdue/src/main/java/org/killbill/billing/overdue/glue/DefaultOverdueModule.java
index 655674d..c79179c 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/glue/DefaultOverdueModule.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/glue/DefaultOverdueModule.java
@@ -28,6 +28,8 @@ import org.killbill.billing.overdue.api.OverdueApi;
import org.killbill.billing.overdue.applicator.OverdueEmailGenerator;
import org.killbill.billing.overdue.applicator.formatters.DefaultOverdueEmailFormatterFactory;
import org.killbill.billing.overdue.applicator.formatters.OverdueEmailFormatterFactory;
+import org.killbill.billing.overdue.caching.EhCacheOverdueConfigCache;
+import org.killbill.billing.overdue.caching.OverdueConfigCache;
import org.killbill.billing.overdue.listener.OverdueListener;
import org.killbill.billing.overdue.notification.OverdueAsyncBusNotifier;
import org.killbill.billing.overdue.notification.OverdueAsyncBusPoster;
@@ -56,6 +58,8 @@ public class DefaultOverdueModule extends KillBillModule implements OverdueModul
protected void configure() {
installOverdueUserApi();
+ installOverdueConfigCache();
+
// internal bindings
installOverdueService();
installOverdueWrapperFactory();
@@ -91,4 +95,8 @@ public class DefaultOverdueModule extends KillBillModule implements OverdueModul
bind(OverdueInternalApi.class).to(DefaultOverdueInternalApi.class).asEagerSingleton();
bind(OverdueApi.class).to(DefaultOverdueApi.class).asEagerSingleton();
}
+
+ public void installOverdueConfigCache() {
+ bind(OverdueConfigCache.class).to(EhCacheOverdueConfigCache.class).asEagerSingleton();
+ }
}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/listener/OverdueListener.java b/overdue/src/main/java/org/killbill/billing/overdue/listener/OverdueListener.java
index dccb0b6..a8d11b9 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/listener/OverdueListener.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/listener/OverdueListener.java
@@ -24,11 +24,16 @@ import javax.inject.Named;
import org.killbill.billing.ObjectType;
import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.events.ControlTagCreationInternalEvent;
import org.killbill.billing.events.ControlTagDeletionInternalEvent;
import org.killbill.billing.events.InvoiceAdjustmentInternalEvent;
import org.killbill.billing.events.PaymentErrorInternalEvent;
import org.killbill.billing.events.PaymentInfoInternalEvent;
+import org.killbill.billing.overdue.OverdueService;
+import org.killbill.billing.overdue.api.OverdueApiException;
+import org.killbill.billing.overdue.api.OverdueConfig;
+import org.killbill.billing.overdue.caching.OverdueConfigCache;
import org.killbill.billing.overdue.config.DefaultOverdueConfig;
import org.killbill.billing.overdue.config.DefaultOverdueState;
import org.killbill.billing.overdue.glue.DefaultOverdueModule;
@@ -53,54 +58,56 @@ public class OverdueListener {
private final InternalCallContextFactory internalCallContextFactory;
private final OverduePoster asyncPoster;
private final Clock clock;
-
- private DefaultOverdueConfig config;
+ private final OverdueConfigCache overdueConfigCache;
private static final Logger log = LoggerFactory.getLogger(OverdueListener.class);
@Inject
public OverdueListener(final Clock clock,
@Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED) final OverduePoster asyncPoster,
+ final OverdueConfigCache overdueConfigCache,
final InternalCallContextFactory internalCallContextFactory) {
this.asyncPoster = asyncPoster;
this.clock = clock;
+ this.overdueConfigCache = overdueConfigCache;
this.internalCallContextFactory = internalCallContextFactory;
}
@Subscribe
public void handle_OVERDUE_ENFORCEMENT_OFF_Insert(final ControlTagCreationInternalEvent event) {
if (event.getTagDefinition().getName().equals(ControlTagType.OVERDUE_ENFORCEMENT_OFF.toString()) && event.getObjectType() == ObjectType.ACCOUNT) {
- insertBusEventIntoNotificationQueue(event.getObjectId(), event, OverdueAsyncBusNotificationAction.CLEAR);
+ insertBusEventIntoNotificationQueue(event.getObjectId(), event, OverdueAsyncBusNotificationAction.CLEAR, event.getSearchKey2());
}
}
@Subscribe
public void handle_OVERDUE_ENFORCEMENT_OFF_Removal(final ControlTagDeletionInternalEvent event) {
if (event.getTagDefinition().getName().equals(ControlTagType.OVERDUE_ENFORCEMENT_OFF.toString()) && event.getObjectType() == ObjectType.ACCOUNT) {
- insertBusEventIntoNotificationQueue(event.getObjectId(), event, OverdueAsyncBusNotificationAction.REFRESH);
+ insertBusEventIntoNotificationQueue(event.getObjectId(), event, OverdueAsyncBusNotificationAction.REFRESH, event.getSearchKey2());
}
}
@Subscribe
public void handlePaymentInfoEvent(final PaymentInfoInternalEvent event) {
log.debug("Received PaymentInfo event {}", event);
- insertBusEventIntoNotificationQueue(event.getAccountId(), event, OverdueAsyncBusNotificationAction.REFRESH);
+ insertBusEventIntoNotificationQueue(event.getAccountId(), event, OverdueAsyncBusNotificationAction.REFRESH, event.getSearchKey2());
}
@Subscribe
public void handlePaymentErrorEvent(final PaymentErrorInternalEvent event) {
log.debug("Received PaymentError event {}", event);
- insertBusEventIntoNotificationQueue(event.getAccountId(), event, OverdueAsyncBusNotificationAction.REFRESH);
+ insertBusEventIntoNotificationQueue(event.getAccountId(), event, OverdueAsyncBusNotificationAction.REFRESH, event.getSearchKey2());
}
@Subscribe
public void handleInvoiceAdjustmentEvent(final InvoiceAdjustmentInternalEvent event) {
log.debug("Received InvoiceAdjustment event {}", event);
- insertBusEventIntoNotificationQueue(event.getAccountId(), event, OverdueAsyncBusNotificationAction.REFRESH);
+ insertBusEventIntoNotificationQueue(event.getAccountId(), event, OverdueAsyncBusNotificationAction.REFRESH, event.getSearchKey2());
}
- private void insertBusEventIntoNotificationQueue(final UUID accountId, final BusEvent event, final OverdueAsyncBusNotificationAction action) {
- final boolean shouldInsertNotification = shouldInsertNotification();
+ private void insertBusEventIntoNotificationQueue(final UUID accountId, final BusEvent event, final OverdueAsyncBusNotificationAction action, final Long tenantRecordId) {
+ final InternalTenantContext tenantContext = internalCallContextFactory.createInternalTenantContext(tenantRecordId, null);
+ final boolean shouldInsertNotification = shouldInsertNotification(tenantContext);
if (shouldInsertNotification) {
final OverdueAsyncBusNotificationKey notificationKey = new OverdueAsyncBusNotificationKey(accountId, action);
@@ -109,25 +116,27 @@ public class OverdueListener {
}
// Optimization: don't bother running the Overdue machinery if it's disabled
- private boolean shouldInsertNotification() {
- if (config == null || config.getOverdueStatesAccount() == null || config.getOverdueStatesAccount().getStates() == null) {
+ private boolean shouldInsertNotification(final InternalTenantContext internalTenantContext) {
+ OverdueConfig overdueConfig;
+ try {
+ overdueConfig = overdueConfigCache.getOverdueConfig(internalTenantContext);
+ } catch (OverdueApiException e) {
+ log.warn("Failed to extract overdue config for tenant " + internalTenantContext.getTenantRecordId());
+ overdueConfig = null;
+ }
+ if (overdueConfig == null || overdueConfig.getOverdueStatesAccount() == null || overdueConfig.getOverdueStatesAccount().getStates() == null) {
return false;
}
- for (final DefaultOverdueState state : config.getOverdueStatesAccount().getStates()) {
+ for (final DefaultOverdueState state : ((DefaultOverdueConfig) overdueConfig).getOverdueStatesAccount().getStates()) {
if (state.getConditionEvaluation() != null) {
return true;
}
}
-
return false;
}
private InternalCallContext createCallContext(final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
return internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "OverdueService", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
}
-
- public void setOverdueConfig(final DefaultOverdueConfig config) {
- this.config = config;
- }
}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/service/DefaultOverdueService.java b/overdue/src/main/java/org/killbill/billing/overdue/service/DefaultOverdueService.java
index ef5cfcf..d7f37b7 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/service/DefaultOverdueService.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/service/DefaultOverdueService.java
@@ -23,18 +23,22 @@ import java.net.URISyntaxException;
import javax.inject.Named;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.lifecycle.api.BusService;
-import org.killbill.billing.overdue.OverdueInternalApi;
import org.killbill.billing.overdue.OverdueProperties;
import org.killbill.billing.overdue.OverdueService;
-import org.killbill.billing.overdue.api.DefaultOverdueInternalApi;
+import org.killbill.billing.overdue.api.OverdueApiException;
+import org.killbill.billing.overdue.api.OverdueConfig;
+import org.killbill.billing.overdue.caching.EhCacheOverdueConfigCache;
+import org.killbill.billing.overdue.caching.OverdueConfigCache;
import org.killbill.billing.overdue.config.DefaultOverdueConfig;
import org.killbill.billing.overdue.glue.DefaultOverdueModule;
import org.killbill.billing.overdue.listener.OverdueListener;
import org.killbill.billing.overdue.notification.OverdueNotifier;
-import org.killbill.billing.overdue.wrapper.OverdueWrapperFactory;
import org.killbill.billing.platform.api.LifecycleHandlerType;
import org.killbill.billing.platform.api.LifecycleHandlerType.LifecycleLevel;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.bus.api.PersistentBus.EventBusException;
import org.killbill.xmlloader.XMLLoader;
import org.slf4j.Logger;
@@ -48,34 +52,31 @@ public class DefaultOverdueService implements OverdueService {
public static final String OVERDUE_SERVICE_NAME = "overdue-service";
- private final OverdueInternalApi userApi;
private final OverdueProperties properties;
private final OverdueNotifier asyncNotifier;
private final OverdueNotifier checkNotifier;
private final BusService busService;
private final OverdueListener listener;
- private final OverdueWrapperFactory factory;
+
+ private final OverdueConfigCache overdueConfigCache;
private DefaultOverdueConfig overdueConfig;
private boolean isConfigLoaded;
@Inject
- public DefaultOverdueService(
- final OverdueInternalApi userApi,
- final OverdueProperties properties,
- @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED) final OverdueNotifier checkNotifier,
- @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED) final OverdueNotifier asyncNotifier,
- final BusService busService,
- final OverdueListener listener,
- final OverdueWrapperFactory factory) {
- this.userApi = userApi;
+ public DefaultOverdueService(final OverdueProperties properties,
+ @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED) final OverdueNotifier checkNotifier,
+ @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED) final OverdueNotifier asyncNotifier,
+ final BusService busService,
+ final OverdueListener listener,
+ final OverdueConfigCache overdueConfigCache) {
this.properties = properties;
this.checkNotifier = checkNotifier;
this.asyncNotifier = asyncNotifier;
this.busService = busService;
this.listener = listener;
- this.factory = factory;
this.isConfigLoaded = false;
+ this.overdueConfigCache = overdueConfigCache;
}
@Override
@@ -83,38 +84,16 @@ public class DefaultOverdueService implements OverdueService {
return OVERDUE_SERVICE_NAME;
}
- @Override
- public OverdueInternalApi getUserApi() {
- return userApi;
- }
-
@LifecycleHandlerType(LifecycleLevel.LOAD_CATALOG)
public synchronized void loadConfig() throws ServiceException {
if (!isConfigLoaded) {
try {
- final URI u = new URI(properties.getConfigURI());
- overdueConfig = XMLLoader.getObjectFromUri(u, DefaultOverdueConfig.class);
- // File not found?
- if (overdueConfig == null) {
- log.warn("Overdue system disabled: unable to load the overdue config from " + properties.getConfigURI());
- overdueConfig = new DefaultOverdueConfig();
- }
-
+ overdueConfigCache.loadDefaultOverdueConfig(properties.getConfigURI());
isConfigLoaded = true;
- } catch (final URISyntaxException e) {
+ } catch (OverdueApiException e) {
log.warn("Overdue system disabled: unable to load the overdue config from " + properties.getConfigURI(), e);
- overdueConfig = new DefaultOverdueConfig();
- } catch (final IllegalArgumentException e) {
- log.warn("Overdue system disabled: unable to load the overdue config from " + properties.getConfigURI(), e);
- overdueConfig = new DefaultOverdueConfig();
- } catch (final Exception e) {
- log.warn("Unable to load the overdue config from " + properties.getConfigURI(), e);
- throw new ServiceException(e);
+ e.printStackTrace();
}
-
- factory.setOverdueConfig(overdueConfig);
- listener.setOverdueConfig(overdueConfig);
- ((DefaultOverdueInternalApi) userApi).setOverdueConfig(overdueConfig);
}
}
@@ -149,4 +128,9 @@ public class DefaultOverdueService implements OverdueService {
checkNotifier.stop();
asyncNotifier.stop();
}
+
+ @Override
+ public OverdueConfig getOverdueConfig(final InternalTenantContext internalTenantContext) throws OverdueApiException {
+ return overdueConfigCache.getOverdueConfig(internalTenantContext);
+ }
}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapperFactory.java b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapperFactory.java
index c234726..c224c83 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapperFactory.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapperFactory.java
@@ -19,22 +19,25 @@ package org.killbill.billing.overdue.wrapper;
import java.util.UUID;
import org.joda.time.Period;
-import org.killbill.billing.overdue.config.DefaultOverdueConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
-import org.killbill.clock.Clock;
+import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.junction.BlockingInternalApi;
+import org.killbill.billing.overdue.OverdueService;
+import org.killbill.billing.overdue.api.OverdueApiException;
+import org.killbill.billing.overdue.api.OverdueConfig;
import org.killbill.billing.overdue.applicator.OverdueStateApplicator;
+import org.killbill.billing.overdue.caching.OverdueConfigCache;
import org.killbill.billing.overdue.calculator.BillingStateCalculator;
+import org.killbill.billing.overdue.config.DefaultOverdueConfig;
import org.killbill.billing.overdue.config.DefaultOverdueState;
import org.killbill.billing.overdue.config.DefaultOverdueStateSet;
import org.killbill.billing.overdue.config.api.OverdueException;
import org.killbill.billing.overdue.config.api.OverdueStateSet;
-import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.junction.BlockingInternalApi;
+import org.killbill.clock.Clock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
@@ -47,23 +50,24 @@ public class OverdueWrapperFactory {
private final OverdueStateApplicator overdueStateApplicator;
private final BlockingInternalApi api;
private final Clock clock;
- private DefaultOverdueConfig config;
+ private final OverdueConfigCache overdueConfigCache;
@Inject
public OverdueWrapperFactory(final BlockingInternalApi api, final Clock clock,
final BillingStateCalculator billingStateCalculator,
final OverdueStateApplicator overdueStateApplicatorBundle,
+ final OverdueConfigCache overdueConfigCache,
final AccountInternalApi accountApi) {
this.billingStateCalculator = billingStateCalculator;
this.overdueStateApplicator = overdueStateApplicatorBundle;
this.accountApi = accountApi;
this.api = api;
this.clock = clock;
+ this.overdueConfigCache = overdueConfigCache;
}
-
@SuppressWarnings("unchecked")
- public OverdueWrapper createOverdueWrapperFor(final Account blockable) throws OverdueException {
- return (OverdueWrapper) new OverdueWrapper(blockable, api, getOverdueStateSet(),
+ public OverdueWrapper createOverdueWrapperFor(final Account blockable, final InternalTenantContext context) throws OverdueException {
+ return (OverdueWrapper) new OverdueWrapper(blockable, api, getOverdueStateSet(context),
clock, billingStateCalculator, overdueStateApplicator);
}
@@ -71,37 +75,39 @@ public class OverdueWrapperFactory {
public OverdueWrapper createOverdueWrapperFor(final UUID id, final InternalTenantContext context) throws OverdueException {
try {
- Account account = accountApi.getAccountById(id, context);
- return new OverdueWrapper(account, api, getOverdueStateSet(),
+ final Account account = accountApi.getAccountById(id, context);
+ return new OverdueWrapper(account, api, getOverdueStateSet(context),
clock, billingStateCalculator, overdueStateApplicator);
-
} catch (AccountApiException e) {
throw new OverdueException(e);
}
}
- private OverdueStateSet getOverdueStateSet() {
- if (config == null || config.getOverdueStatesAccount() == null) {
- return new DefaultOverdueStateSet() {
-
- @SuppressWarnings("unchecked")
- @Override
- public DefaultOverdueState[] getStates() {
- return new DefaultOverdueState[0];
- }
- @Override
- public Period getInitialReevaluationInterval() {
- return null;
- }
- };
- } else {
- return config.getOverdueStatesAccount();
+ private OverdueStateSet getOverdueStateSet(final InternalTenantContext context) throws OverdueException {
+ final OverdueConfig overdueConfig;
+ try {
+ overdueConfig = overdueConfigCache.getOverdueConfig(context);
+ if (overdueConfig == null || overdueConfig.getOverdueStatesAccount() == null) {
+ return new DefaultOverdueStateSet() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public DefaultOverdueState[] getStates() {
+ return new DefaultOverdueState[0];
+ }
+
+ @Override
+ public Period getInitialReevaluationInterval() {
+ return null;
+ }
+ };
+ } else {
+ return ((DefaultOverdueConfig) overdueConfig).getOverdueStatesAccount();
+ }
+ } catch (OverdueApiException e) {
+ throw new OverdueException(e);
}
}
-
- public void setOverdueConfig(final DefaultOverdueConfig config) {
- this.config = config;
- }
-
}
+
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java b/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
index 457696e..ac23e0a 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
@@ -44,7 +44,6 @@ public class TestOverdueStateApplicator extends OverdueTestSuiteWithEmbeddedDB {
public void testApplicator() throws Exception {
final InputStream is = new ByteArrayInputStream(testOverdueHelper.getConfigXml().getBytes());
final DefaultOverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class);
- overdueWrapperFactory.setOverdueConfig(config);
final Account account = Mockito.mock(Account.class);
Mockito.when(account.getId()).thenReturn(UUID.randomUUID());
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/caching/MockOverdueConfigCache.java b/overdue/src/test/java/org/killbill/billing/overdue/caching/MockOverdueConfigCache.java
new file mode 100644
index 0000000..7d88488
--- /dev/null
+++ b/overdue/src/test/java/org/killbill/billing/overdue/caching/MockOverdueConfigCache.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.overdue.caching;
+
+import javax.inject.Inject;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.overdue.api.OverdueApiException;
+import org.killbill.billing.overdue.api.OverdueConfig;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
+
+public class MockOverdueConfigCache extends EhCacheOverdueConfigCache implements OverdueConfigCache
+{
+
+ private OverdueConfig overwriteDefaultOverdueConfig;
+
+ @Inject
+ public MockOverdueConfigCache(final CacheControllerDispatcher cacheControllerDispatcher) {
+ super(cacheControllerDispatcher);
+ }
+
+ @Override
+ public void loadDefaultOverdueConfig(final String url) throws OverdueApiException {
+ super.loadDefaultOverdueConfig(url);
+ }
+
+ public void loadOverwriteDefaultOverdueConfig(final OverdueConfig overdueConfig) throws OverdueApiException {
+ this.overwriteDefaultOverdueConfig = overdueConfig;
+ }
+
+ public void clearOverwriteDefaultOverdueConfig() {
+ this.overwriteDefaultOverdueConfig = null;
+ }
+
+ @Override
+ public OverdueConfig getOverdueConfig(final InternalTenantContext tenantContext) throws OverdueApiException {
+ if (overwriteDefaultOverdueConfig != null) {
+ return overwriteDefaultOverdueConfig;
+ }
+ return super.getOverdueConfig(tenantContext);
+ }
+}
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java b/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
index bac5878..0284e6d 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
@@ -25,6 +25,9 @@ import org.killbill.billing.mock.glue.MockTagModule;
import org.killbill.billing.mock.glue.MockTenantModule;
import org.killbill.billing.overdue.TestOverdueHelper;
import org.killbill.billing.overdue.applicator.OverdueBusListenerTester;
+import org.killbill.billing.overdue.caching.EhCacheOverdueConfigCache;
+import org.killbill.billing.overdue.caching.MockOverdueConfigCache;
+import org.killbill.billing.overdue.caching.OverdueConfigCache;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.util.email.EmailModule;
import org.killbill.billing.util.email.templates.TemplateModule;
@@ -62,4 +65,9 @@ public class TestOverdueModule extends DefaultOverdueModule {
bind(OverdueBusListenerTester.class).asEagerSingleton();
bind(TestOverdueHelper.class).asEagerSingleton();
}
+
+ public void installOverdueConfigCache() {
+ bind(OverdueConfigCache.class).to(MockOverdueConfigCache.class).asEagerSingleton();
+ }
+
}
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java b/overdue/src/test/java/org/killbill/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
index b89b3c0..1253410 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
@@ -27,6 +27,7 @@ import org.killbill.billing.junction.BlockingInternalApi;
import org.killbill.billing.lifecycle.api.BusService;
import org.killbill.billing.overdue.applicator.OverdueBusListenerTester;
import org.killbill.billing.overdue.applicator.OverdueStateApplicator;
+import org.killbill.billing.overdue.caching.OverdueConfigCache;
import org.killbill.billing.overdue.calculator.BillingStateCalculator;
import org.killbill.billing.overdue.glue.DefaultOverdueModule;
import org.killbill.billing.overdue.glue.TestOverdueModuleWithEmbeddedDB;
@@ -95,6 +96,8 @@ public abstract class OverdueTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
protected NonEntityDao nonEntityDao;
@Inject
protected TestOverdueHelper testOverdueHelper;
+ @Inject
+ protected OverdueConfigCache overdueConfigCache;
@BeforeClass(groups = "slow")
protected void beforeClass() throws Exception {
@@ -108,6 +111,7 @@ public abstract class OverdueTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
cacheControllerDispatcher.clearAll();
bus.start();
bus.register(listener);
+ service.loadConfig();
service.initialize();
service.start();
}
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java b/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
index 644e19f..927af22 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
@@ -19,23 +19,30 @@ package org.killbill.billing.overdue.wrapper;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.junction.DefaultBlockingState;
+import org.killbill.billing.overdue.OverdueTestSuiteWithEmbeddedDB;
import org.killbill.billing.overdue.api.OverdueState;
+import org.killbill.billing.overdue.caching.MockOverdueConfigCache;
import org.killbill.billing.overdue.config.DefaultOverdueConfig;
+import org.killbill.xmlloader.XMLLoader;
import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import org.killbill.billing.account.api.Account;
-import org.killbill.billing.overdue.OverdueTestSuiteWithEmbeddedDB;
-import org.killbill.xmlloader.XMLLoader;
-import org.killbill.billing.junction.DefaultBlockingState;
-
public class TestOverdueWrapper extends OverdueTestSuiteWithEmbeddedDB {
+ @BeforeMethod(groups = "slow")
+ public void beforeMethod() throws Exception {
+ super.beforeMethod();
+ ((MockOverdueConfigCache) overdueConfigCache).loadOverwriteDefaultOverdueConfig(null);
+ }
+
@Test(groups = "slow")
public void testWrapperBasic() throws Exception {
final InputStream is = new ByteArrayInputStream(testOverdueHelper.getConfigXml().getBytes());
final DefaultOverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class);
- overdueWrapperFactory.setOverdueConfig(config);
+ ((MockOverdueConfigCache) overdueConfigCache).loadOverwriteDefaultOverdueConfig(config);
Account account;
OverdueWrapper wrapper;
@@ -43,26 +50,25 @@ public class TestOverdueWrapper extends OverdueTestSuiteWithEmbeddedDB {
state = config.getOverdueStatesAccount().findState("OD1");
account = testOverdueHelper.createAccount(clock.getUTCToday().minusDays(31));
- wrapper = overdueWrapperFactory.createOverdueWrapperFor(account);
+ wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
wrapper.refresh(internalCallContext);
testOverdueHelper.checkStateApplied(state);
state = config.getOverdueStatesAccount().findState("OD2");
account = testOverdueHelper.createAccount(clock.getUTCToday().minusDays(41));
- wrapper = overdueWrapperFactory.createOverdueWrapperFor(account);
+ wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
wrapper.refresh(internalCallContext);
testOverdueHelper.checkStateApplied(state);
state = config.getOverdueStatesAccount().findState("OD3");
account = testOverdueHelper.createAccount(clock.getUTCToday().minusDays(51));
- wrapper = overdueWrapperFactory.createOverdueWrapperFor(account);
+ wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
wrapper.refresh(internalCallContext);
testOverdueHelper.checkStateApplied(state);
}
@Test(groups = "slow")
public void testWrapperNoConfig() throws Exception {
- overdueWrapperFactory.setOverdueConfig(null);
final Account account;
final OverdueWrapper wrapper;
@@ -72,7 +78,7 @@ public class TestOverdueWrapper extends OverdueTestSuiteWithEmbeddedDB {
final DefaultOverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class);
state = config.getOverdueStatesAccount().findState(DefaultBlockingState.CLEAR_STATE_NAME);
account = testOverdueHelper.createAccount(clock.getUTCToday().minusDays(31));
- wrapper = overdueWrapperFactory.createOverdueWrapperFor(account);
+ wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
final OverdueState result = wrapper.refresh(internalCallContext);
Assert.assertEquals(result.getName(), state.getName());
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java b/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
index 4d27d09..fa9454b 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
@@ -40,4 +40,10 @@ public class DefaultTenantInternalApi implements TenantInternalApi {
public List<String> getTenantCatalogs(final InternalTenantContext tenantContext) {
return tenantDao.getTenantValueForKey(TenantKey.CATALOG.toString(), tenantContext);
}
+
+ @Override
+ public String getTenantOverdueConfig(final InternalTenantContext tenantContext) {
+ final List<String> values = tenantDao.getTenantValueForKey(TenantKey.OVERDUE_CONFIG.toString(), tenantContext);
+ return values.isEmpty() ? null : values.get(0);
+ }
}
diff --git a/util/src/main/java/org/killbill/billing/util/cache/Cachable.java b/util/src/main/java/org/killbill/billing/util/cache/Cachable.java
index a3f3fd1..024bdff 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/Cachable.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/Cachable.java
@@ -32,6 +32,7 @@ public @interface Cachable {
public final String AUDIT_LOG_CACHE_NAME = "audit-log";
public final String AUDIT_LOG_VIA_HISTORY_CACHE_NAME = "audit-log-via-history";
public final String TENANT_CATALOG_CACHE_NAME = "tenant-catalog";
+ public final String TENANT_OVERDUE_CONFIG_CACHE_NAME = "tenant-overdue-config";
public CacheType value();
@@ -55,7 +56,10 @@ public @interface Cachable {
AUDIT_LOG_VIA_HISTORY(AUDIT_LOG_VIA_HISTORY_CACHE_NAME, true),
/* Tenant catalog cache */
- TENANT_CATALOG(TENANT_CATALOG_CACHE_NAME, false);
+ TENANT_CATALOG(TENANT_CATALOG_CACHE_NAME, false),
+
+ /* Tenant overdue config cache */
+ TENANT_OVERDUE_CONFIG(TENANT_OVERDUE_CONFIG_CACHE_NAME, false);
private final String cacheName;
private final boolean isKeyPrefixedWithTableName;
diff --git a/util/src/main/java/org/killbill/billing/util/cache/EhCacheCacheManagerProvider.java b/util/src/main/java/org/killbill/billing/util/cache/EhCacheCacheManagerProvider.java
index adea4d8..ab5eaa5 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/EhCacheCacheManagerProvider.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/EhCacheCacheManagerProvider.java
@@ -46,7 +46,8 @@ public class EhCacheCacheManagerProvider implements Provider<CacheManager> {
final ObjectIdCacheLoader objectIdCacheLoader,
final AuditLogCacheLoader auditLogCacheLoader,
final AuditLogViaHistoryCacheLoader auditLogViaHistoryCacheLoader,
- final TenantCatalogCacheLoader tenantCatalogCacheLoader) {
+ final TenantCatalogCacheLoader tenantCatalogCacheLoader,
+ final TenantOverdueConfigCacheLoader tenantOverdueConfigCacheLoader) {
this.cacheConfig = cacheConfig;
cacheLoaders.add(recordIdCacheLoader);
cacheLoaders.add(accountRecordIdCacheLoader);
@@ -55,6 +56,7 @@ public class EhCacheCacheManagerProvider implements Provider<CacheManager> {
cacheLoaders.add(auditLogCacheLoader);
cacheLoaders.add(auditLogViaHistoryCacheLoader);
cacheLoaders.add(tenantCatalogCacheLoader);
+ cacheLoaders.add(tenantOverdueConfigCacheLoader);
}
@Override
@@ -78,10 +80,8 @@ public class EhCacheCacheManagerProvider implements Provider<CacheManager> {
for (final CacheLoader existingCacheLoader : cache.getRegisteredCacheLoaders()) {
cache.unregisterCacheLoader(existingCacheLoader);
}
-
cache.registerCacheLoader(cacheLoader);
}
-
return cacheManager;
}
}
diff --git a/util/src/main/java/org/killbill/billing/util/cache/TenantOverdueConfigCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/TenantOverdueConfigCacheLoader.java
new file mode 100644
index 0000000..3665bc0
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/cache/TenantOverdueConfigCacheLoader.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.util.cache;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.overdue.api.OverdueApiException;
+import org.killbill.billing.tenant.api.TenantInternalApi;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+
+@Singleton
+public class TenantOverdueConfigCacheLoader extends BaseCacheLoader {
+
+ private final TenantInternalApi tenantApi;
+
+ @Inject
+ public TenantOverdueConfigCacheLoader(final TenantInternalApi tenantApi) {
+ super();
+ this.tenantApi = tenantApi;
+ }
+
+ @Override
+ public CacheType getCacheType() {
+ return CacheType.TENANT_OVERDUE_CONFIG;
+ }
+
+ @Override
+ public Object load(final Object key, final Object argument) {
+ checkCacheLoaderStatus();
+
+ if (!(key instanceof InternalTenantContext)) {
+ throw new IllegalArgumentException("Unexpected key type of " + key.getClass().getName());
+ }
+ if (!(argument instanceof CacheLoaderArgument)) {
+ throw new IllegalArgumentException("Unexpected argument type of " + argument.getClass().getName());
+ }
+
+ final InternalTenantContext internalTenantContext = (InternalTenantContext) key;
+ final CacheLoaderArgument cacheLoaderArgument = (CacheLoaderArgument) argument;
+
+ if (cacheLoaderArgument.getArgs() == null || !(cacheLoaderArgument.getArgs()[0] instanceof LoaderCallback)) {
+ throw new IllegalArgumentException("Missing LoaderCallback from the arguments ");
+ }
+
+ final LoaderCallback callback = (LoaderCallback) cacheLoaderArgument.getArgs()[0];
+
+ final String overdueXML = tenantApi.getTenantOverdueConfig(internalTenantContext);
+ if (overdueXML == null) {
+ return null;
+ }
+ try {
+ return callback.loadCatalog(overdueXML);
+ } catch (OverdueApiException e) {
+ throw new IllegalStateException(String.format("Failed to de-serialize overdue config for tenant %s : %s",
+ internalTenantContext.getTenantRecordId(), e.getMessage()), e);
+ }
+ }
+
+ public interface LoaderCallback {
+
+ public Object loadCatalog(final String overdueXML) throws OverdueApiException;
+ }
+}
util/src/main/resources/ehcache.xml 13(+13 -0)
diff --git a/util/src/main/resources/ehcache.xml b/util/src/main/resources/ehcache.xml
index a97dbe9..7159b93 100644
--- a/util/src/main/resources/ehcache.xml
+++ b/util/src/main/resources/ehcache.xml
@@ -129,5 +129,18 @@
properties=""/>
</cache>
+ <cache name="tenant-overdue-config"
+ maxElementsInMemory="1000"
+ maxElementsOnDisk="0"
+ overflowToDisk="false"
+ diskPersistent="false"
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
+ <cacheEventListenerFactory
+ class="org.killbill.billing.util.cache.ExpirationListenerFactory"
+ properties=""/>
+ </cache>
+
</ehcache>
diff --git a/util/src/test/java/org/killbill/billing/mock/glue/MockOverdueModule.java b/util/src/test/java/org/killbill/billing/mock/glue/MockOverdueModule.java
index 3749060..0a88273 100644
--- a/util/src/test/java/org/killbill/billing/mock/glue/MockOverdueModule.java
+++ b/util/src/test/java/org/killbill/billing/mock/glue/MockOverdueModule.java
@@ -21,12 +21,16 @@ package org.killbill.billing.mock.glue;
import org.killbill.billing.glue.OverdueModule;
import org.killbill.billing.overdue.OverdueInternalApi;
import org.killbill.billing.overdue.api.OverdueApi;
+import org.killbill.billing.overdue.api.OverdueConfig;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.util.glue.KillBillModule;
import org.mockito.Mockito;
+import com.google.inject.Inject;
+
public class MockOverdueModule extends KillBillModule implements OverdueModule {
+ @Inject
public MockOverdueModule(final KillbillConfigSource configSource) {
super(configSource);
}
@@ -37,6 +41,7 @@ public class MockOverdueModule extends KillBillModule implements OverdueModule {
bind(OverdueApi.class).toInstance(Mockito.mock(OverdueApi.class));
}
+
@Override
protected void configure() {
installOverdueUserApi();