killbill-aplcache

overdue: optimize config caching Put a placeholder in the

3/18/2015 3:52:42 PM

Details

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
index 2624064..d52470c 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/caching/EhCacheOverdueConfigCache.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/caching/EhCacheOverdueConfigCache.java
@@ -53,6 +53,15 @@ public class EhCacheOverdueConfigCache implements OverdueConfigCache {
     public EhCacheOverdueConfigCache(final CacheControllerDispatcher cacheControllerDispatcher) {
         this.cacheController = cacheControllerDispatcher.getCacheController(CacheType.TENANT_OVERDUE_CONFIG);
         this.cacheLoaderArgument = initializeCacheLoaderArgument();
+
+        try {
+            // Provided in the classpath
+            final URI noOverdueConfigURI = new URI("NoOverdueConfig.xml");
+            defaultOverdueConfig = XMLLoader.getObjectFromUri(noOverdueConfigURI, DefaultOverdueConfig.class);
+        } catch (final Exception e) {
+            defaultOverdueConfig = new DefaultOverdueConfig();
+            log.warn("Exception loading NoOverdueConfig - should never happen!", e);
+        }
     }
 
     @Override
@@ -71,7 +80,6 @@ public class EhCacheOverdueConfigCache implements OverdueConfigCache {
             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);
         }
     }
@@ -84,9 +92,6 @@ public class EhCacheOverdueConfigCache implements OverdueConfigCache {
     @Override
     public OverdueConfig getOverdueConfig(final InternalTenantContext tenantContext) throws OverdueApiException {
         if (tenantContext.getTenantRecordId() == InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID) {
-            if (defaultOverdueConfig == null) {
-                throw new OverdueApiException(ErrorCode.OVERDUE_NOT_CONFIGURED);
-            }
             return defaultOverdueConfig;
         }
         // The cache loader might choke on some bad xml -- unlikely since we check its validity prior storing it,
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/caching/TestEhCacheOverdueConfigCache.java b/overdue/src/test/java/org/killbill/billing/overdue/caching/TestEhCacheOverdueConfigCache.java
index 1cb8c1b..50f6c17 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/caching/TestEhCacheOverdueConfigCache.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/caching/TestEhCacheOverdueConfigCache.java
@@ -68,7 +68,8 @@ public class TestEhCacheOverdueConfigCache extends OverdueTestSuiteNoDB {
         overdueConfigCache.loadDefaultOverdueConfig((String) null);
         final OverdueConfig result = overdueConfigCache.getOverdueConfig(internalCallContext);
         Assert.assertNotNull(result);
-        Assert.assertEquals(result.getOverdueStatesAccount().getStates().length, 0);
+        Assert.assertEquals(result.getOverdueStatesAccount().getStates().length, 1);
+        Assert.assertTrue(result.getOverdueStatesAccount().getStates()[0].isClearState());
     }
 
     //
@@ -98,9 +99,12 @@ public class TestEhCacheOverdueConfigCache extends OverdueTestSuiteNoDB {
     //
     @Test(groups = "fast")
     public void testExistingTenantOverdue() throws OverdueApiException, URISyntaxException, IOException {
+        final InternalCallContext differentMultiTenantContext = Mockito.mock(InternalCallContext.class);
+        Mockito.when(differentMultiTenantContext.getTenantRecordId()).thenReturn(55667788L);
+
         final AtomicBoolean shouldThrow = new AtomicBoolean(false);
         final Long multiTenantRecordId = multiTenantContext.getTenantRecordId();
-        overdueConfigCache.loadDefaultOverdueConfig(Resources.getResource("OverdueConfig.xml").toExternalForm());
+        final Long otherMultiTenantRecordId = otherMultiTenantContext.getTenantRecordId();
 
         final InputStream tenantInputOverdueConfig = UriAccessor.accessUri(new URI(Resources.getResource("OverdueConfig2.xml").toExternalForm()));
         final String tenantOverdueConfigXML = CharStreams.toString(new InputStreamReader(tenantInputOverdueConfig, "UTF-8"));
@@ -115,12 +119,33 @@ public class TestEhCacheOverdueConfigCache extends OverdueTestSuiteNoDB {
                 final InternalTenantContext internalContext = (InternalTenantContext) invocation.getArguments()[0];
                 if (multiTenantRecordId.equals(internalContext.getTenantRecordId())) {
                     return tenantOverdueConfigXML;
-                } else {
+                } else if (otherMultiTenantRecordId.equals(internalContext.getTenantRecordId())) {
                     return otherTenantOverdueConfigXML;
+                } else {
+                    return null;
                 }
             }
         });
 
+        // Verify the lookup for a non-cached tenant. No system config is set yet but EhCacheOverdueConfigCache returns a default no-op one
+        OverdueConfig differentResult = overdueConfigCache.getOverdueConfig(differentMultiTenantContext);
+        Assert.assertNotNull(differentResult);
+        Assert.assertEquals(differentResult.getOverdueStatesAccount().getStates().length, 1);
+        Assert.assertTrue(differentResult.getOverdueStatesAccount().getStates()[0].isClearState());
+
+        // Make sure the cache loader isn't invoked, see https://github.com/killbill/killbill/issues/298
+        shouldThrow.set(true);
+
+        differentResult = overdueConfigCache.getOverdueConfig(differentMultiTenantContext);
+        Assert.assertNotNull(differentResult);
+        Assert.assertEquals(differentResult.getOverdueStatesAccount().getStates().length, 1);
+        Assert.assertTrue(differentResult.getOverdueStatesAccount().getStates()[0].isClearState());
+
+        shouldThrow.set(false);
+
+        // Set a default config
+        overdueConfigCache.loadDefaultOverdueConfig(Resources.getResource("OverdueConfig.xml").toExternalForm());
+
         // Verify the lookup for this tenant
         final OverdueConfig result = overdueConfigCache.getOverdueConfig(multiTenantContext);
         Assert.assertNotNull(result);
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
index d4a9a58..81ebe00 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/TenantOverdueConfigCacheLoader.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/TenantOverdueConfigCacheLoader.java
@@ -67,7 +67,7 @@ public class TenantOverdueConfigCacheLoader extends BaseCacheLoader {
         final LoaderCallback callback = (LoaderCallback) cacheLoaderArgument.getArgs()[0];
         final String overdueXML = tenantApi.getTenantOverdueConfig(internalTenantContext);
         if (overdueXML == null) {
-            return null;
+            return EMPTY_VALUE_PLACEHOLDER;
         }
         try {
             log.info("Loading overdue cache for tenant " + internalTenantContext.getTenantRecordId());