killbill-aplcache

catalog: Fix catalog initialization wiring and exception

12/19/2016 8:49:36 PM

Details

diff --git a/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java b/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
index 2adf38c..8ece25c 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
@@ -17,12 +17,17 @@
 package org.killbill.billing.catalog.api.user;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
+import java.net.URISyntaxException;
 
 import javax.inject.Inject;
+import javax.xml.bind.JAXBException;
+import javax.xml.transform.TransformerException;
 
 import org.joda.time.DateTime;
+import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.CatalogUpdater;
 import org.killbill.billing.catalog.StandaloneCatalog;
@@ -33,6 +38,7 @@ import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
 import org.killbill.billing.catalog.api.CatalogUserApi;
+import org.killbill.billing.catalog.api.InvalidConfigException;
 import org.killbill.billing.catalog.api.SimplePlanDescriptor;
 import org.killbill.billing.catalog.api.StaticCatalog;
 import org.killbill.billing.catalog.caching.CatalogCache;
@@ -42,7 +48,9 @@ import org.killbill.billing.tenant.api.TenantUserApi;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.xmlloader.ValidationException;
 import org.killbill.xmlloader.XMLLoader;
+import org.xml.sax.SAXException;
 
 public class DefaultCatalogUserApi implements CatalogUserApi {
 
@@ -77,19 +85,34 @@ public class DefaultCatalogUserApi implements CatalogUserApi {
 
     @Override
     public void uploadCatalog(final String catalogXML, final CallContext callContext) throws CatalogApiException {
+
+
+        final InternalTenantContext internalTenantContext = createInternalTenantContext(callContext);
         try {
             // Validation purpose:  Will throw if bad XML or catalog validation fails
             final InputStream stream = new ByteArrayInputStream(catalogXML.getBytes());
             XMLLoader.getObjectFromStream(new URI("dummy"), stream, StandaloneCatalog.class);
 
-            final InternalTenantContext internalTenantContext = createInternalTenantContext(callContext);
             catalogCache.clearCatalog(internalTenantContext);
             tenantApi.addTenantKeyValue(TenantKey.CATALOG.toString(), catalogXML, callContext);
-        } catch (TenantApiException e) {
+        } catch (final TenantApiException e) {
             throw new CatalogApiException(e);
-        } catch (final Exception e) {
+        } catch (final ValidationException e) {
+            throw new CatalogApiException(ErrorCode.CAT_INVALID_FOR_TENANT, internalTenantContext.getTenantRecordId());
+        } catch (final JAXBException e) {
+            throw new CatalogApiException(ErrorCode.CAT_INVALID_FOR_TENANT, internalTenantContext.getTenantRecordId());
+        } catch (final IOException e) {
+            throw new IllegalStateException(e);
+        } catch (final TransformerException e) {
+            throw new IllegalStateException(e);
+        } catch (final URISyntaxException e) {
+            throw new IllegalStateException(e);
+        } catch (final SAXException e) {
+            throw new IllegalStateException(e);
+        } catch (final InvalidConfigException e) {
             throw new IllegalStateException(e);
         }
+
     }
 
 
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java b/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
index 80217c8..6014008 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
@@ -19,6 +19,7 @@
 package org.killbill.billing.catalog.io;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URI;
@@ -27,22 +28,33 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.xml.bind.JAXBException;
+import javax.xml.transform.TransformerException;
+
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.catalog.StandaloneCatalog;
 import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
 import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.InvalidConfigException;
 import org.killbill.billing.catalog.override.PriceOverride;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.clock.Clock;
 import org.killbill.xmlloader.UriAccessor;
+import org.killbill.xmlloader.ValidationErrors;
+import org.killbill.xmlloader.ValidationException;
 import org.killbill.xmlloader.XMLLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
 
 import com.google.common.io.Resources;
 import com.google.inject.Inject;
 
 public class VersionedCatalogLoader implements CatalogLoader {
 
+    private static final Logger logger = LoggerFactory.getLogger(VersionedCatalogLoader.class);
+
     private static final Object PROTOCOL_FOR_FILE = "file";
     private static final String XML_EXTENSION = ".xml";
 
@@ -75,9 +87,21 @@ public class VersionedCatalogLoader implements CatalogLoader {
                 final StandaloneCatalog catalog = XMLLoader.getObjectFromUri(u, StandaloneCatalog.class);
                 result.add(new StandaloneCatalogWithPriceOverride(catalog, priceOverride, InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID, internalCallContextFactory));
             }
+            // Perform initialization and validation for VersionedCatalog
+            XMLLoader.initializeAndValidate(new URI(uriString), result);
             return result;
+        } catch (final ValidationException e) {
+            logger.warn("Failed to load default catalog", e);
+            throw new CatalogApiException(ErrorCode.CAT_INVALID_DEFAULT);
+        } catch (final JAXBException e) {
+            logger.warn("Failed to load default catalog", e);
+            throw new CatalogApiException(ErrorCode.CAT_INVALID_DEFAULT, e);
+        } catch(IllegalArgumentException e) {
+            logger.warn("Failed to load default catalog", e);
+            throw new CatalogApiException(ErrorCode.CAT_INVALID_DEFAULT, e);
         } catch (Exception e) {
-            throw new CatalogApiException(ErrorCode.CAT_INVALID_DEFAULT, "Problem encountered loading catalog: ", e.getMessage());
+            logger.warn("Failed to load default catalog", e);
+            throw new IllegalStateException(e);
         }
     }
 
@@ -103,11 +127,30 @@ public class VersionedCatalogLoader implements CatalogLoader {
                     result.add(new StandaloneCatalogWithPriceOverride(catalog, priceOverride, tenantRecordId, internalCallContextFactory));
                 }
             }
+            // Perform initialization and validation for VersionedCatalog
+            XMLLoader.initializeAndValidate(uri, result);
             return result;
-        } catch (final CatalogApiException e) {
-            throw e;
-        } catch (final Exception e) {
+        } catch (final ValidationException e) {
+            logger.warn("Failed to load catalog for tenant='{}'",  tenantRecordId, e);
+            throw new CatalogApiException(ErrorCode.CAT_INVALID_FOR_TENANT, tenantRecordId);
+        } catch (final JAXBException e) {
+            logger.warn("Failed to load catalog for tenant='{}'",  tenantRecordId, e);
             throw new CatalogApiException(ErrorCode.CAT_INVALID_FOR_TENANT, tenantRecordId);
+        } catch (final IOException e) {
+            logger.warn("Failed to load catalog for tenant='{}'",  tenantRecordId, e);
+            throw new IllegalStateException(e);
+        } catch (final TransformerException e) {
+            logger.warn("Failed to load catalog for tenant='{}'",  tenantRecordId, e);
+            throw new IllegalStateException(e);
+        } catch (final URISyntaxException e) {
+            logger.warn("Failed to load catalog for tenant='{}'",  tenantRecordId, e);
+            throw new IllegalStateException(e);
+        } catch (final SAXException e) {
+            logger.warn("Failed to load catalog for tenant='{}'",  tenantRecordId, e);
+            throw new IllegalStateException(e);
+        } catch (final InvalidConfigException e) {
+            logger.warn("Failed to load catalog for tenant='{}'",  tenantRecordId, e);
+            throw new IllegalStateException(e);
         }
     }
 
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
index aa53bda..df49615 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -407,11 +407,13 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
     //
     @Override
     public void initialize(final VersionedCatalog catalog, final URI sourceURI) {
+        //
+        // Initialization is performed first on each StandaloneCatalog (XMLLoader#initializeAndValidate)
+        // and then later on the VersionedCatalog, so we only initialize and validate VersionedCatalog
+        // *without** recursively through each StandaloneCatalog
+        //
         super.initialize(catalog, sourceURI);
         CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
-        for (final StandaloneCatalog c : versions) {
-            c.initialize(c, sourceURI);
-        }
     }
 
     @Override