killbill-aplcache
Changes
catalog/src/main/resources/EmptyCatalog.xml 67(+67 -0)
Details
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheCatalogCache.java b/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheCatalogCache.java
index 8f31169..ef3806d 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheCatalogCache.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheCatalogCache.java
@@ -36,6 +36,8 @@ import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.annotations.VisibleForTesting;
+
public class EhCacheCatalogCache implements CatalogCache {
private final Logger logger = LoggerFactory.getLogger(EhCacheCatalogCache.class);
@@ -51,20 +53,19 @@ public class EhCacheCatalogCache implements CatalogCache {
this.cacheController = cacheControllerDispatcher.getCacheController(CacheType.TENANT_CATALOG);
this.loader = loader;
this.cacheLoaderArgument = initializeCacheLoaderArgument(this);
+ setDefaultCatalog();
}
@Override
public void loadDefaultCatalog(final String url) throws CatalogApiException {
- defaultCatalog = (url != null) ? loader.loadDefaultCatalog(url) : null;
+ if (url != null) {
+ defaultCatalog = loader.loadDefaultCatalog(url);
+ }
}
@Override
public VersionedCatalog getCatalog(final InternalTenantContext tenantContext) throws CatalogApiException {
if (tenantContext.getTenantRecordId() == InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID) {
- if (defaultCatalog == null) {
- throw new CatalogApiException(ErrorCode.CAT_INVALID_DEFAULT,
- "the system property org.killbill.catalog.uri must be specified and point to valid catalog xml");
- }
return defaultCatalog;
}
// The cache loader might choke on some bad xml -- unlikely since we check its validity prior storing it,
@@ -108,4 +109,15 @@ public class EhCacheCatalogCache implements CatalogCache {
final InternalTenantContext notUsed = null;
return new CacheLoaderArgument(irrelevant, args, notUsed);
}
+
+ @VisibleForTesting
+ void setDefaultCatalog() {
+ try {
+ // Provided in the classpath
+ this.defaultCatalog = loader.loadDefaultCatalog("EmptyCatalog.xml");
+ } catch (final CatalogApiException e) {
+ this.defaultCatalog = new VersionedCatalog();
+ logger.warn("Exception loading EmptyCatalog - should never happen!", e);
+ }
+ }
}
catalog/src/main/resources/EmptyCatalog.xml 67(+67 -0)
diff --git a/catalog/src/main/resources/EmptyCatalog.xml b/catalog/src/main/resources/EmptyCatalog.xml
new file mode 100644
index 0000000..c3d9dff
--- /dev/null
+++ b/catalog/src/main/resources/EmptyCatalog.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ ~ Copyright 2015 Groupon, Inc
+ ~ Copyright 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.
+ -->
+
+<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+
+ <effectiveDate>2013-02-08T00:00:00+00:00</effectiveDate>
+ <catalogName>EmptyCatalog</catalogName>
+
+ <recurringBillingMode>IN_ADVANCE</recurringBillingMode>
+
+ <currencies>
+ <currency>USD</currency>
+ </currencies>
+
+ <products>
+ <product name="empty">
+ <category>BASE</category>
+ </product>
+ </products>
+
+ <rules>
+ </rules>
+
+ <plans>
+ <plan name="empty-monthly">
+ <product>empty</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>0</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ </plans>
+
+ <priceLists>
+ <defaultPriceList name="DEFAULT">
+ <plans>
+ <plan>empty-monthly</plan>
+ </plans>
+ </defaultPriceList>
+ </priceLists>
+</catalog>
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/caching/TestEhCacheCatalogCache.java b/catalog/src/test/java/org/killbill/billing/catalog/caching/TestEhCacheCatalogCache.java
index 998f2ae..d2e4e19 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/caching/TestEhCacheCatalogCache.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/caching/TestEhCacheCatalogCache.java
@@ -30,6 +30,7 @@ import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.CatalogTestSuiteNoDB;
import org.killbill.billing.catalog.DefaultProduct;
import org.killbill.billing.catalog.VersionedCatalog;
+import org.killbill.billing.catalog.api.Catalog;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.xmlloader.UriAccessor;
import org.mockito.Mockito;
@@ -59,15 +60,17 @@ public class TestEhCacheCatalogCache extends CatalogTestSuiteNoDB {
otherMultiTenantContext = Mockito.mock(InternalCallContext.class);
Mockito.when(otherMultiTenantContext.getAccountRecordId()).thenReturn(123L);
Mockito.when(otherMultiTenantContext.getTenantRecordId()).thenReturn(112233L);
+
+ ((EhCacheCatalogCache) catalogCache).setDefaultCatalog();
}
//
- // Verify CatalogCache throws CatalogApiException when used in mono-tenant and catalog system property has not been set
+ // Verify CatalogCache returns default Catalog when used in mono-tenant and catalog system property has not been set
//
- @Test(groups = "fast", expectedExceptions = CatalogApiException.class)
+ @Test(groups = "fast")
public void testMissingDefaultCatalog() throws CatalogApiException {
catalogCache.loadDefaultCatalog(null);
- catalogCache.getCatalog(internalCallContext);
+ Assert.assertEquals(catalogCache.getCatalog(internalCallContext).getCatalogName(), "EmptyCatalog");
}
//
@@ -99,9 +102,12 @@ public class TestEhCacheCatalogCache extends CatalogTestSuiteNoDB {
//
@Test(groups = "fast")
public void testExistingTenantCatalog() throws CatalogApiException, 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();
- catalogCache.loadDefaultCatalog(Resources.getResource("SpyCarBasic.xml").toExternalForm());
+ final Long otherMultiTenantRecordId = otherMultiTenantContext.getTenantRecordId();
final InputStream tenantInputCatalog = UriAccessor.accessUri(new URI(Resources.getResource("SpyCarAdvanced.xml").toExternalForm()));
final String tenantCatalogXML = CharStreams.toString(new InputStreamReader(tenantInputCatalog, "UTF-8"));
@@ -116,12 +122,31 @@ public class TestEhCacheCatalogCache extends CatalogTestSuiteNoDB {
final InternalTenantContext internalContext = (InternalTenantContext) invocation.getArguments()[0];
if (multiTenantRecordId.equals(internalContext.getTenantRecordId())) {
return ImmutableList.<String>of(tenantCatalogXML);
- } else {
+ } else if (otherMultiTenantRecordId.equals(internalContext.getTenantRecordId())) {
return ImmutableList.<String>of(otherTenantCatalogXML);
+ } else {
+ return ImmutableList.<String>of();
}
}
});
+ // Verify the lookup for a non-cached tenant. No system config is set yet but EhCacheCatalogCache returns a default empty one
+ VersionedCatalog differentResult = catalogCache.getCatalog(differentMultiTenantContext);
+ Assert.assertNotNull(differentResult);
+ Assert.assertEquals(differentResult.getCatalogName(), "EmptyCatalog");
+
+ // Make sure the cache loader isn't invoked, see https://github.com/killbill/killbill/issues/300
+ shouldThrow.set(true);
+
+ differentResult = catalogCache.getCatalog(differentMultiTenantContext);
+ Assert.assertNotNull(differentResult);
+ Assert.assertEquals(differentResult.getCatalogName(), "EmptyCatalog");
+
+ shouldThrow.set(false);
+
+ // Set a default config
+ catalogCache.loadDefaultCatalog(Resources.getResource("SpyCarBasic.xml").toExternalForm());
+
// Verify the lookup for this tenant
final VersionedCatalog result = catalogCache.getCatalog(multiTenantContext);
Assert.assertNotNull(result);