killbill-memoizeit
Changes
catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseBillingAlignment.java 13(+13 -0)
catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanAlignment.java 17(+17 -0)
catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanPolicy.java 37(+32 -5)
catalog/src/main/resources/EmptyCatalog.xml 10(+10 -0)
pom.xml 2(+1 -1)
Details
diff --git a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v1.xml b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v1.xml
index 4701c94..5a977b6 100644
--- a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v1.xml
+++ b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v1.xml
@@ -68,12 +68,20 @@
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
+ <changePolicyCase>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
<alignment>START_OF_SUBSCRIPTION</alignment>
</changeAlignmentCase>
</changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>END_OF_TERM</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
<createAlignment>
<createAlignmentCase>
<product>Laser-Scope</product>
diff --git a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v2.xml b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v2.xml
index d75891d..c575b09 100644
--- a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v2.xml
+++ b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v2.xml
@@ -68,12 +68,20 @@
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
+ <changePolicyCase>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
<alignment>START_OF_SUBSCRIPTION</alignment>
</changeAlignmentCase>
</changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>END_OF_TERM</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
<createAlignment>
<createAlignmentCase>
<product>Laser-Scope</product>
diff --git a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v3.xml b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v3.xml
index 8ad8ba4..63acb70 100644
--- a/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v3.xml
+++ b/beatrix/src/test/resources/retiredCatalogs/WeaponsHireSmall-v3.xml
@@ -66,12 +66,20 @@
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
+ <changePolicyCase>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
<alignment>START_OF_SUBSCRIPTION</alignment>
</changeAlignmentCase>
</changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>END_OF_TERM</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
<createAlignment>
<createAlignmentCase>
<product>Laser-Scope</product>
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..5c6482d 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,9 +48,11 @@ 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 {
+public class DefaultCatalogUserApi implements CatalogUserApi {
private final CatalogService catalogService;
private final InternalCallContextFactory internalCallContextFactory;
@@ -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(e, ErrorCode.CAT_INVALID_FOR_TENANT, internalTenantContext.getTenantRecordId());
+ } catch (final JAXBException e) {
+ throw new CatalogApiException(e, 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/caching/EhCacheOverriddenPlanCache.java b/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheOverriddenPlanCache.java
index 3b54252..f0b3f7c 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheOverriddenPlanCache.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheOverriddenPlanCache.java
@@ -27,6 +27,7 @@ import org.killbill.billing.ObjectType;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.DefaultPlan;
import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
+import org.killbill.billing.catalog.StandaloneCatalog;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.Plan;
@@ -93,7 +94,9 @@ public class EhCacheOverriddenPlanCache implements OverriddenPlanCache {
final DefaultPlan defaultPlan = (DefaultPlan) catalog.findCurrentPlan(parentPlanName);
final PlanPhasePriceOverride[] overrides = createOverrides(defaultPlan, phaseDefs);
- return new DefaultPlan(planName, defaultPlan, overrides);
+ final DefaultPlan result = new DefaultPlan(planName, defaultPlan, overrides);
+ result.initialize((StandaloneCatalog) catalog, ((StandaloneCatalog) catalog).getCatalogURI());
+ return result;
}
private PlanPhasePriceOverride[] createOverrides(final Plan defaultPlan, final List<CatalogOverridePhaseDefinitionModelDao> phaseDefs) {
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/CatalogSafetyInitializer.java b/catalog/src/main/java/org/killbill/billing/catalog/CatalogSafetyInitializer.java
index 996d2f1..68d90d8 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/CatalogSafetyInitializer.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/CatalogSafetyInitializer.java
@@ -19,32 +19,47 @@ package org.killbill.billing.catalog;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
+import org.killbill.billing.catalog.api.BlockType;
+import org.killbill.billing.catalog.api.FixedType;
+
public class CatalogSafetyInitializer {
+ public static final Integer DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE = -1;
+
+ private static final Map<Class, LinkedList<Field>> perCatalogClassNonRequiredFields = new HashMap<Class, LinkedList<Field>>();
+
//
// Ensure that all uninitialized arrays for which there is neither a 'required' XmlElementWrapper or XmlElement annotation
// end up initialized with a default zero length array (allowing to safely get the length and iterate over (0) element.
//
- public static void initializeNonRequiredArrayFields(final Object obj) {
+ public static void initializeNonRequiredNullFieldsWithDefaultValue(final Object obj) {
+
+ LinkedList<Field> fields = perCatalogClassNonRequiredFields.get(obj.getClass());
+ if (fields == null) {
+ fields = initializeNonRequiredFields(obj.getClass());
+ perCatalogClassNonRequiredFields.put(obj.getClass(), fields);
+ }
try {
- final Field[] fields = obj.getClass().getDeclaredFields();
for (final Field f : fields) {
if (f.getType().isArray()) {
- final XmlElementWrapper xmlElementWrapper = f.getAnnotation(XmlElementWrapper.class);
- if (xmlElementWrapper != null) {
- if (!xmlElementWrapper.required()) {
- initializeArrayIfNull(obj, f);
- }
- } else {
- final XmlElement xmlElement = f.getAnnotation(XmlElement.class);
- if (xmlElement != null && !xmlElement.required()) {
- initializeArrayIfNull(obj, f);
+ initializeArrayIfNull(obj, f);
+ } else if (!f.getType().isPrimitive()) {
+ if (f.getType().isEnum()) {
+ if (FixedType.class.equals(f.getType())) {
+ initializeFieldWithValue(obj, f, FixedType.ONE_TIME);
+ } else if (BlockType.class.equals(f.getType())) {
+ initializeFieldWithValue(obj, f, BlockType.VANILLA);
}
+ } else if (Integer.class.equals(f.getType())) {
+ initializeFieldWithValue(obj, f, DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE);
}
}
}
@@ -55,6 +70,47 @@ public class CatalogSafetyInitializer {
}
}
+ // For each type of catalog object we keep the 'Field' associated to non required attribute fields
+ private static LinkedList<Field> initializeNonRequiredFields(final Class<?> aClass) {
+
+ final LinkedList<Field> result = new LinkedList();
+ final Field[] fields = aClass.getDeclaredFields();
+ for (final Field f : fields) {
+ if (f.getType().isArray()) {
+ final XmlElementWrapper xmlElementWrapper = f.getAnnotation(XmlElementWrapper.class);
+ if (xmlElementWrapper != null) {
+ if (!xmlElementWrapper.required()) {
+ result.add(f);
+ }
+ } else {
+ final XmlElement xmlElement = f.getAnnotation(XmlElement.class);
+ if (xmlElement != null && !xmlElement.required()) {
+ result.add(f);
+ }
+ }
+ } else if (!f.getType().isPrimitive()) {
+ if (f.getType().isEnum()) {
+ if (FixedType.class.equals(f.getType())) {
+ result.add(f);
+ } else if (BlockType.class.equals(f.getType())) {
+ result.add(f);
+ }
+ } else if (Integer.class.equals(f.getType())) {
+ result.add(f);
+ }
+ }
+ }
+ return result;
+ }
+
+ private static void initializeFieldWithValue(final Object obj, final Field f, final Object value) throws IllegalAccessException, ClassNotFoundException {
+ f.setAccessible(true);
+ if (f.get(obj) == null) {
+ f.set(obj, value);
+ }
+ f.setAccessible(false);
+ }
+
private static void initializeArrayIfNull(final Object obj, final Field f) throws IllegalAccessException, ClassNotFoundException {
f.setAccessible(true);
if (f.get(obj) == null) {
@@ -63,6 +119,7 @@ public class CatalogSafetyInitializer {
f.setAccessible(false);
}
+
private static Object[] getZeroLengthArrayInitializer(final Field f) throws ClassNotFoundException {
// Yack... type erasure, why?
final String arrayClassName = f.getType().getCanonicalName();
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java
index 784e577..6604384 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java
@@ -86,6 +86,11 @@ public class DefaultBlock extends ValidatingConfig<StandaloneCatalog> implements
@Override
public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
+ // Safety check
+ if (type == null) {
+ throw new IllegalStateException("type should have been automatically been initialized with VANILLA ");
+ }
+
if (type == BlockType.TOP_UP && minTopUpCredit == null) {
errors.add(new ValidationError(String.format("TOP_UP block needs to define minTopUpCredit for phase %s",
phase.getName()), catalog.getCatalogURI(), DefaultUsage.class, ""));
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultDuration.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultDuration.java
index 726ea77..b7e5fd4 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultDuration.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultDuration.java
@@ -16,6 +16,8 @@
package org.killbill.billing.catalog;
+import java.net.URI;
+
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@@ -35,7 +37,6 @@ import org.killbill.xmlloader.ValidationErrors;
@XmlAccessorType(XmlAccessType.NONE)
public class DefaultDuration extends ValidatingConfig<StandaloneCatalog> implements Duration {
- public static final int DEFAULT_DURATION_NUMBER = -1;
@XmlElement(required = true)
private TimeUnit unit;
@@ -59,7 +60,6 @@ public class DefaultDuration extends ValidatingConfig<StandaloneCatalog> impleme
}
public DefaultDuration() {
- number = DEFAULT_DURATION_NUMBER;
}
@Override
@@ -102,17 +102,30 @@ public class DefaultDuration extends ValidatingConfig<StandaloneCatalog> impleme
@Override
public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
+
+ // Safety check
+ if (number == null) {
+ throw new IllegalStateException("number should have been automatically been initialized with DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE ");
+ }
+
//Validation: TimeUnit UNLIMITED if number == -1
- if ((unit == TimeUnit.UNLIMITED && number != DEFAULT_DURATION_NUMBER)) {
+ if ((unit == TimeUnit.UNLIMITED && number != CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE)) {
errors.add(new ValidationError("Duration can only have 'UNLIMITED' unit if the number is omitted",
catalog.getCatalogURI(), DefaultDuration.class, ""));
- } else if ((unit != TimeUnit.UNLIMITED) && number == DEFAULT_DURATION_NUMBER) {
+ } else if ((unit != TimeUnit.UNLIMITED) && number == CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE) {
errors.add(new ValidationError("Finite Duration must have a well defined length",
catalog.getCatalogURI(), DefaultDuration.class, ""));
}
return errors;
}
+ @Override
+ public void initialize(final StandaloneCatalog root, final URI uri) {
+ super.initialize(root, uri);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
+ }
+
+
public DefaultDuration setUnit(final TimeUnit unit) {
this.unit = unit;
return this;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultFixed.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultFixed.java
index 1218f4d..924fbf5 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultFixed.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultFixed.java
@@ -16,7 +16,6 @@
package org.killbill.billing.catalog;
-import java.math.BigDecimal;
import java.net.URI;
import javax.xml.bind.annotation.XmlAccessType;
@@ -24,7 +23,6 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
-import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.Fixed;
import org.killbill.billing.catalog.api.FixedType;
import org.killbill.billing.catalog.api.InternationalPrice;
@@ -52,7 +50,6 @@ public class DefaultFixed extends ValidatingConfig<StandaloneCatalog> implements
}
public DefaultFixed() {
- type = FixedType.ONE_TIME;
}
public DefaultFixed(final DefaultFixed in, final PlanPhasePriceOverride override) {
@@ -63,8 +60,7 @@ public class DefaultFixed extends ValidatingConfig<StandaloneCatalog> implements
@Override
public void initialize(final StandaloneCatalog root, final URI uri) {
super.initialize(root, uri);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
-
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
if (fixedPrice != null) {
fixedPrice.initialize(root, uri);
}
@@ -72,6 +68,10 @@ public class DefaultFixed extends ValidatingConfig<StandaloneCatalog> implements
@Override
public ValidationErrors validate(final StandaloneCatalog root, final ValidationErrors errors) {
+ // Safety check
+ if (type == null) {
+ throw new IllegalStateException("fixedPrice should have been automatically been initialized with ONE_TIME ");
+ }
return errors;
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
index 5ff3622..1b391c8 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
@@ -125,7 +125,7 @@ public class DefaultInternationalPrice extends ValidatingConfig<StandaloneCatalo
@Override
public void initialize(final StandaloneCatalog root, final URI uri) {
super.initialize(root, uri);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultLimit.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultLimit.java
index 103d209..30176b5 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultLimit.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultLimit.java
@@ -81,7 +81,7 @@ public class DefaultLimit extends ValidatingConfig<StandaloneCatalog> implements
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
index 25fa3c4..5f2e9ea 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
@@ -75,7 +75,7 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
//No other value is allowed for Tiered ADDONS
//A value of -1 means unlimited
@XmlElement(required = false)
- private Integer plansAllowedInBundle = -1;
+ private Integer plansAllowedInBundle;
private String priceListName;
@@ -174,7 +174,7 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
if (finalPhase != null) {
finalPhase.setPlan(this);
@@ -217,6 +217,10 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
finalPhase.getName(), name, finalPhase.getPhaseType()),
catalog.getCatalogURI(), DefaultPlan.class, ""));
}
+ // Safety check
+ if (plansAllowedInBundle == null) {
+ throw new IllegalStateException("plansAllowedInBundle should have been automatically been initialized with DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE (-1)");
+ }
return errors;
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
index d49ba3e..4a2eade 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
@@ -163,7 +163,7 @@ public class DefaultPlanPhase extends ValidatingConfig<StandaloneCatalog> implem
public void initialize(final StandaloneCatalog root, final URI uri) {
super.initialize(root, uri);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
if (fixed != null) {
fixed.initialize(root, uri);
@@ -177,6 +177,7 @@ public class DefaultPlanPhase extends ValidatingConfig<StandaloneCatalog> implem
usage.initialize(root, uri);
usage.setPhase(this);
}
+ duration.initialize(root, uri);
}
public DefaultPlanPhase setFixed(final DefaultFixed fixed) {
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPrice.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPrice.java
index 6b5f6ec..069ccb6 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPrice.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPrice.java
@@ -83,7 +83,7 @@ public class DefaultPrice extends ValidatingConfig<StandaloneCatalog> implements
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
index 273f12c..a67783a 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
@@ -102,7 +102,7 @@ public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implem
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
public DefaultPriceList setName(final String name) {
@@ -141,4 +141,10 @@ public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implem
result = 31 * result + (plans != null ? plans.hashCode() : 0);
return result;
}
+
+ @Override
+ public String toString() {
+ return "DefaultPriceList{" +
+ "name='" + name + '}';
+ }
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceListSet.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceListSet.java
index 15a479c..4aaf3cb 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceListSet.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceListSet.java
@@ -109,7 +109,7 @@ public class DefaultPriceListSet extends ValidatingConfig<StandaloneCatalog> imp
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultProduct.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultProduct.java
index c8d4999..af95ceb 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultProduct.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultProduct.java
@@ -152,7 +152,7 @@ public class DefaultProduct extends ValidatingConfig<StandaloneCatalog> implemen
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
for (DefaultLimit cur : limits) {
cur.initialize(catalog, sourceURI);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultRecurring.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultRecurring.java
index 14f956a..d4c180b 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultRecurring.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultRecurring.java
@@ -65,7 +65,7 @@ public class DefaultRecurring extends ValidatingConfig<StandaloneCatalog> implem
@Override
public void initialize(final StandaloneCatalog root, final URI uri) {
super.initialize(root, uri);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
if (recurringPrice != null) {
recurringPrice.initialize(root, uri);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java
index 1680036..21ad681 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java
@@ -133,7 +133,7 @@ public class DefaultTier extends ValidatingConfig<StandaloneCatalog> implements
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultUnit.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultUnit.java
index c11f6b9..f82499d 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultUnit.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultUnit.java
@@ -51,7 +51,7 @@ public class DefaultUnit extends ValidatingConfig<StandaloneCatalog> implements
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsage.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsage.java
index cb34f94..59af193 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsage.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsage.java
@@ -165,7 +165,7 @@ public class DefaultUsage extends ValidatingConfig<StandaloneCatalog> implements
@Override
public void initialize(final StandaloneCatalog root, final URI uri) {
super.initialize(root, uri);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
for (DefaultLimit limit : limits) {
limit.initialize(root, uri);
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..edfdf88 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(e, ErrorCode.CAT_INVALID_DEFAULT, uriString);
+ } catch (final JAXBException e) {
+ logger.warn("Failed to load default catalog", e);
+ throw new CatalogApiException(e, ErrorCode.CAT_INVALID_DEFAULT, uriString);
+ } catch(IllegalArgumentException e) {
+ logger.warn("Failed to load default catalog", e);
+ throw new CatalogApiException(e, ErrorCode.CAT_INVALID_DEFAULT, uriString);
} 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) {
- throw new CatalogApiException(ErrorCode.CAT_INVALID_FOR_TENANT, tenantRecordId);
+ } catch (final ValidationException e) {
+ logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
+ throw new CatalogApiException(e, ErrorCode.CAT_INVALID_FOR_TENANT, tenantRecordId);
+ } catch (final JAXBException e) {
+ logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
+ throw new CatalogApiException(e, ErrorCode.CAT_INVALID_FOR_TENANT, tenantRecordId);
+ } catch (final IOException e) {
+ logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
+ throw new IllegalStateException(e);
+ } catch (final TransformerException e) {
+ logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
+ throw new IllegalStateException(e);
+ } catch (final URISyntaxException e) {
+ logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
+ throw new IllegalStateException(e);
+ } catch (final SAXException e) {
+ logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
+ throw new IllegalStateException(e);
+ } catch (final InvalidConfigException e) {
+ logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
+ throw new IllegalStateException(e);
}
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
index 86b8739..822ef14 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
@@ -30,6 +30,8 @@ import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.DefaultPlan;
import org.killbill.billing.catalog.DefaultPlanPhase;
import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
+import org.killbill.billing.catalog.StandaloneCatalog;
+import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
@@ -60,7 +62,7 @@ public class DefaultPriceOverride implements PriceOverride {
}
@Override
- public DefaultPlan getOrCreateOverriddenPlan(final Plan parentPlan, final DateTime catalogEffectiveDate, final List<PlanPhasePriceOverride> overrides, @Nullable final InternalCallContext context) throws CatalogApiException {
+ public DefaultPlan getOrCreateOverriddenPlan(final StandaloneCatalog standaloneCatalog, final Plan parentPlan, final DateTime catalogEffectiveDate, final List<PlanPhasePriceOverride> overrides, @Nullable final InternalCallContext context) throws CatalogApiException {
final PlanPhasePriceOverride[] resolvedOverride = new PlanPhasePriceOverride[parentPlan.getAllPhases().length];
int index = 0;
@@ -110,6 +112,7 @@ public class DefaultPriceOverride implements PriceOverride {
planName = new StringBuffer(parentPlan.getName()).append("-dryrun-").append(DRY_RUN_PLAN_IDX.incrementAndGet()).toString();
}
final DefaultPlan result = new DefaultPlan(planName, (DefaultPlan) parentPlan, resolvedOverride);
+ result.initialize(standaloneCatalog, standaloneCatalog.getCatalogURI());
if (context == null) {
overriddenPlanCache.addDryRunPlan(planName, result);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/override/PriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/override/PriceOverride.java
index 49cdbc8..cb81b5b 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/override/PriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/override/PriceOverride.java
@@ -23,6 +23,8 @@ import org.joda.time.DateTime;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.DefaultPlan;
+import org.killbill.billing.catalog.StandaloneCatalog;
+import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
@@ -30,7 +32,7 @@ import org.killbill.billing.catalog.api.StaticCatalog;
public interface PriceOverride {
- DefaultPlan getOrCreateOverriddenPlan(final Plan parentPlan, final DateTime catalogEffectiveDate, final List<PlanPhasePriceOverride> overrides, final InternalCallContext context) throws CatalogApiException;
+ DefaultPlan getOrCreateOverriddenPlan(final StandaloneCatalog catalog, final Plan parentPlan, final DateTime catalogEffectiveDate, final List<PlanPhasePriceOverride> overrides, final InternalCallContext context) throws CatalogApiException;
DefaultPlan getOverriddenPlan(final String planName, final StaticCatalog catalog, final InternalTenantContext context) throws CatalogApiException;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/PriceListDefault.java b/catalog/src/main/java/org/killbill/billing/catalog/PriceListDefault.java
index 0778ad4..08571ef 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/PriceListDefault.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/PriceListDefault.java
@@ -49,7 +49,7 @@ public class PriceListDefault extends DefaultPriceList {
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
@Override
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
index 319a486..99e23d4 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
@@ -20,7 +20,6 @@ package org.killbill.billing.catalog.rules;
import java.net.URI;
import org.killbill.billing.catalog.CatalogSafetyInitializer;
-import org.killbill.billing.catalog.DefaultPrice;
import org.killbill.billing.catalog.DefaultPriceList;
import org.killbill.billing.catalog.DefaultProduct;
import org.killbill.billing.catalog.StandaloneCatalog;
@@ -98,7 +97,7 @@ public abstract class DefaultCase<T> extends ValidatingConfig<StandaloneCatalog>
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
protected abstract DefaultCase<T> setProduct(Product product);
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseBillingAlignment.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseBillingAlignment.java
index fc2b8f5..31e56fc 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseBillingAlignment.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseBillingAlignment.java
@@ -74,4 +74,17 @@ public class DefaultCaseBillingAlignment extends DefaultCasePhase<BillingAlignme
result = 31 * result + (alignment != null ? alignment.hashCode() : 0);
return result;
}
+
+ @Override
+ public String toString() {
+ return "DefaultCaseBillingAlignment {" +
+ "alignment=" + alignment +
+ ", phaseType=" + getPhaseType() +
+ ", product=" + getProduct() +
+ ", productCategory=" + getProductCategory() +
+ ", billingPeriod=" + getBillingPeriod() +
+ ", priceList=" + getPriceList() +
+ '}';
+ }
+
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseCancelPolicy.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseCancelPolicy.java
index b1a061c..11a3399 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseCancelPolicy.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseCancelPolicy.java
@@ -74,4 +74,17 @@ public class DefaultCaseCancelPolicy extends DefaultCasePhase<BillingActionPolic
result = 31 * result + (policy != null ? policy.hashCode() : 0);
return result;
}
+
+ @Override
+ public String toString() {
+ return "DefaultCaseCancelPolicy{" +
+ "policy =" + policy +
+ ", phaseType =" + getPhaseType() +
+ ", product=" + getProduct() +
+ ", productCategory=" + getProductCategory() +
+ ", billingPeriod=" + getBillingPeriod() +
+ ", priceList=" + getPriceList() +
+ '}';
+ }
+
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
index 62a83cb..d522bff 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
@@ -155,7 +155,7 @@ public abstract class DefaultCaseChange<T> extends ValidatingConfig<StandaloneCa
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
public DefaultCaseChange<T> setPhaseType(final PhaseType phaseType) {
@@ -303,4 +303,19 @@ public abstract class DefaultCaseChange<T> extends ValidatingConfig<StandaloneCa
public PriceList getToPriceList() {
return toPriceList;
}
+
+ @Override
+ public String toString() {
+ return "DefaultCaseChange{" +
+ "phaseType=" + phaseType +
+ ", fromProduct=" + fromProduct +
+ ", fromProductCategory=" + fromProductCategory +
+ ", fromBillingPeriod=" + fromBillingPeriod +
+ ", fromPriceList=" + fromPriceList +
+ ", toProduct=" + toProduct +
+ ", toProductCategory=" + toProductCategory +
+ ", toBillingPeriod=" + toBillingPeriod +
+ ", toPriceList=" + toPriceList +
+ '}';
+ }
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanAlignment.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanAlignment.java
index f01860c..d3a95b6 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanAlignment.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanAlignment.java
@@ -68,4 +68,21 @@ public class DefaultCaseChangePlanAlignment extends DefaultCaseChange<PlanAlignm
result = 31 * result + (alignment != null ? alignment.hashCode() : 0);
return result;
}
+
+ @Override
+ public String toString() {
+ return "DefaultCaseChangePlanAlignment {" +
+ "alignment=" + alignment +
+ ", phaseType=" + getPhaseType() +
+ ", fromProduct=" + getFromProduct() +
+ ", fromProductCategory=" + getFromProductCategory() +
+ ", fromBillingPeriod=" + getFromBillingPeriod() +
+ ", fromPriceList=" + getFromPriceList() +
+ ", toProduct=" + getToProduct() +
+ ", toProductCategory=" + getToProductCategory() +
+ ", toBillingPeriod=" + getToBillingPeriod() +
+ ", toPriceList=" + getToPriceList() +
+ '}';
+ }
+
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanPolicy.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanPolicy.java
index 1464b73..71f90b5 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanPolicy.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChangePlanPolicy.java
@@ -16,16 +16,16 @@
package org.killbill.billing.catalog.rules;
+import java.net.URI;
+
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
+import org.killbill.billing.catalog.CatalogSafetyInitializer;
+import org.killbill.billing.catalog.StandaloneCatalog;
import org.killbill.billing.catalog.api.BillingActionPolicy;
-import org.killbill.billing.catalog.api.BillingPeriod;
-import org.killbill.billing.catalog.api.PhaseType;
-import org.killbill.billing.catalog.api.PriceList;
-import org.killbill.billing.catalog.api.Product;
-import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.catalog.api.rules.CaseChangePlanPolicy;
+import org.killbill.xmlloader.ValidationErrors;
@XmlSeeAlso(DefaultCaseChange.class)
public class DefaultCaseChangePlanPolicy extends DefaultCaseChange<BillingActionPolicy> implements CaseChangePlanPolicy {
@@ -49,6 +49,17 @@ public class DefaultCaseChangePlanPolicy extends DefaultCaseChange<BillingAction
}
@Override
+ public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
+ return errors;
+ }
+
+ @Override
+ public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
+ super.initialize(catalog, sourceURI);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
+ }
+
+ @Override
public boolean equals(final Object o) {
if (this == o) {
return true;
@@ -75,4 +86,20 @@ public class DefaultCaseChangePlanPolicy extends DefaultCaseChange<BillingAction
result = 31 * result + (policy != null ? policy.hashCode() : 0);
return result;
}
+
+ @Override
+ public String toString() {
+ return "DefaultCaseChangePlanPolicy {" +
+ "policy=" + policy +
+ ", phaseType=" + phaseType +
+ ", fromProduct=" + getFromProduct() +
+ ", fromProductCategory=" + getFromProductCategory() +
+ ", fromBillingPeriod=" + getFromBillingPeriod() +
+ ", fromPriceList=" + getFromPriceList() +
+ ", toProduct=" + getToProduct() +
+ ", toProductCategory=" + getToProductCategory() +
+ ", toBillingPeriod=" + getToBillingPeriod() +
+ ", toPriceList=" + getToPriceList() +
+ '}';
+ }
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseCreateAlignment.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseCreateAlignment.java
index 5d7862d..5577db3 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseCreateAlignment.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseCreateAlignment.java
@@ -68,4 +68,16 @@ public class DefaultCaseCreateAlignment extends DefaultCaseStandardNaming<PlanAl
result = 31 * result + (alignment != null ? alignment.hashCode() : 0);
return result;
}
+
+ @Override
+ public String toString() {
+ return "DefaultCaseCreateAlignment {" +
+ "alignment =" + alignment +
+ ", product=" + getProduct() +
+ ", productCategory=" + getProductCategory() +
+ ", billingPeriod=" + getBillingPeriod() +
+ ", priceList=" + getPriceList() +
+ '}';
+ }
+
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePhase.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePhase.java
index d36db6c..ef8773c 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePhase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePhase.java
@@ -63,7 +63,7 @@ public abstract class DefaultCasePhase<T> extends DefaultCaseStandardNaming<T> {
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePriceList.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePriceList.java
index 7958365..4b9cf33 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePriceList.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePriceList.java
@@ -143,4 +143,16 @@ public class DefaultCasePriceList extends DefaultCaseStandardNaming<DefaultPrice
result = 31 * result + (toPriceList != null ? toPriceList.hashCode() : 0);
return result;
}
+
+
+ @Override
+ public String toString() {
+ return "DefaultCasePriceList {" +
+ "fromProduct=" + fromProduct +
+ ", fromProductCategory=" + fromProductCategory +
+ ", fromBillingPeriod=" + fromBillingPeriod +
+ ", fromPriceList=" + fromPriceList +
+ ", toPriceList=" + toPriceList +
+ '}';
+ }
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseStandardNaming.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseStandardNaming.java
index 79c73aa..d23c55f 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseStandardNaming.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseStandardNaming.java
@@ -115,4 +115,5 @@ public abstract class DefaultCaseStandardNaming<T> extends DefaultCase<T> implem
result = 31 * result + (priceList != null ? priceList.hashCode() : 0);
return result;
}
+
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
index 20c4e9c..bc7f4ae 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
@@ -18,6 +18,7 @@ package org.killbill.billing.catalog.rules;
import java.net.URI;
import java.util.Arrays;
+import java.util.HashSet;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@@ -45,6 +46,7 @@ import org.killbill.billing.catalog.api.rules.CaseCreateAlignment;
import org.killbill.billing.catalog.api.rules.CasePriceList;
import org.killbill.billing.catalog.api.rules.PlanRules;
import org.killbill.xmlloader.ValidatingConfig;
+import org.killbill.xmlloader.ValidationError;
import org.killbill.xmlloader.ValidationErrors;
import com.google.common.collect.ImmutableList;
@@ -157,7 +159,7 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
}
private DefaultPriceList findPriceList(final PlanSpecifier specifier, final StaticCatalog catalog) throws CatalogApiException {
- DefaultPriceList result = DefaultCase.getResult(priceListCase, specifier, catalog);
+ DefaultPriceList result = DefaultCasePriceList.getResult(priceListCase, specifier, catalog);
if (result == null) {
final String priceListName = specifier.getPlanName() != null ? catalog.findCurrentPlan(specifier.getPlanName()).getPriceListName() : specifier.getPriceListName();
result = (DefaultPriceList) catalog.findCurrentPricelist(priceListName);
@@ -165,13 +167,92 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
return result;
}
+
@Override
public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
- //TODO: MDW - Validation: check that the plan change special case pairs are unique!
- //TODO: MDW - Validation: check that the each product appears in at most one tier.
- //TODO: MDW - Unit tests for rules
- //TODO: MDW - validate that there is a default policy for change AND cancel
+ //
+ // Validate that there is a default policy for change AND cancel rules and check unicity of rules
+ //
+ final HashSet<DefaultCaseChangePlanPolicy> caseChangePlanPoliciesSet = new HashSet<DefaultCaseChangePlanPolicy>();
+ boolean foundDefaultCase = false;
+ for (final DefaultCaseChangePlanPolicy cur : changeCase) {
+ if (caseChangePlanPoliciesSet.contains(cur)) {
+ errors.add(new ValidationError(String.format("Duplicate rule for change plan %s", cur.toString()), catalog.getCatalogURI(), DefaultPlanRules.class, ""));
+ } else {
+ caseChangePlanPoliciesSet.add(cur);
+ }
+ if (cur.getPhaseType() == null &&
+ cur.getFromProduct() == null &&
+ cur.getFromProductCategory() == null &&
+ cur.getFromBillingPeriod() == null &&
+ cur.getFromPriceList() == null &&
+ cur.getToProduct() == null &&
+ cur.getToProductCategory() == null &&
+ cur.getToBillingPeriod() == null &&
+ cur.getToPriceList() == null) {
+ foundDefaultCase = true;
+ }
+ }
+ if (!foundDefaultCase) {
+ errors.add(new ValidationError("Missing default rule case for plan change", catalog.getCatalogURI(), DefaultPlanRules.class, ""));
+ }
+
+ final HashSet<DefaultCaseCancelPolicy> defaultCaseCancelPoliciesSet = new HashSet<DefaultCaseCancelPolicy>();
+ foundDefaultCase = false;
+ for (final DefaultCaseCancelPolicy cur : cancelCase) {
+ if (defaultCaseCancelPoliciesSet.contains(cur)) {
+ errors.add(new ValidationError(String.format("Duplicate rule for plan cancellation %s", cur.toString()), catalog.getCatalogURI(), DefaultPlanRules.class, ""));
+ } else {
+ defaultCaseCancelPoliciesSet.add(cur);
+ }
+ if (cur.getPhaseType() == null &&
+ cur.getProduct() == null &&
+ cur.getProductCategory() == null &&
+ cur.getBillingPeriod() == null &&
+ cur.getPriceList() == null) {
+ foundDefaultCase = true;
+ }
+ }
+ if (!foundDefaultCase) {
+ errors.add(new ValidationError("Missing default rule case for plan cancellation", catalog.getCatalogURI(), DefaultPlanRules.class, ""));
+ }
+
+
+ final HashSet<DefaultCaseChangePlanAlignment> caseChangePlanAlignmentsSet = new HashSet<DefaultCaseChangePlanAlignment>();
+ for (final DefaultCaseChangePlanAlignment cur : changeAlignmentCase) {
+ if (caseChangePlanAlignmentsSet.contains(cur)) {
+ errors.add(new ValidationError(String.format("Duplicate rule for plan change alignment %s", cur.toString()), catalog.getCatalogURI(), DefaultPlanRules.class, ""));
+ } else {
+ caseChangePlanAlignmentsSet.add(cur);
+ }
+ }
+
+ final HashSet<DefaultCaseCreateAlignment> caseCreateAlignmentsSet = new HashSet<DefaultCaseCreateAlignment>();
+ for (final DefaultCaseCreateAlignment cur : createAlignmentCase) {
+ if (caseCreateAlignmentsSet.contains(cur)) {
+ errors.add(new ValidationError(String.format("Duplicate rule for create plan alignment %s", cur.toString()), catalog.getCatalogURI(), DefaultPlanRules.class, ""));
+ } else {
+ caseCreateAlignmentsSet.add(cur);
+ }
+ }
+ final HashSet<DefaultCaseBillingAlignment> caseBillingAlignmentsSet = new HashSet<DefaultCaseBillingAlignment>();
+ for (final DefaultCaseBillingAlignment cur : billingAlignmentCase) {
+ if (caseBillingAlignmentsSet.contains(cur)) {
+ errors.add(new ValidationError(String.format("Duplicate rule for billing alignment %s", cur.toString()), catalog.getCatalogURI(), DefaultPlanRules.class, ""));
+ } else {
+ caseBillingAlignmentsSet.add(cur);
+ }
+ }
+
+ final HashSet<DefaultCasePriceList> casePriceListsSet = new HashSet<DefaultCasePriceList>();
+ for (final DefaultCasePriceList cur : priceListCase) {
+ if (casePriceListsSet.contains(cur)) {
+ errors.add(new ValidationError(String.format("Duplicate rule for price list transition %s", cur.toString()), catalog.getCatalogURI(), DefaultPlanRules.class, ""));
+ } else {
+ casePriceListsSet.add(cur);
+ }
+ }
return errors;
}
@@ -179,7 +260,7 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
@Override
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
for (final DefaultCaseChangePlanPolicy cur : changeCase) {
cur.initialize(catalog, sourceURI);
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
index 81366e4..96869e4 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
@@ -300,7 +300,7 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
super.initialize(catalog, sourceURI);
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(this);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
catalogURI = sourceURI;
planRules.initialize(catalog, sourceURI);
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
index 8a42e4b..7e6deb9 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
@@ -79,7 +79,7 @@ public class StandaloneCatalogWithPriceOverride extends StandaloneCatalog implem
}
final InternalCallContext internalCallContext = overrides.getCallContext() != null ? internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(overrides.getCallContext()) : null;
- return priceOverride.getOrCreateOverriddenPlan(defaultPlan, CatalogDateHelper.toUTCDateTime(getEffectiveDate()), overrides.getOverrides(), internalCallContext);
+ return priceOverride.getOrCreateOverriddenPlan(this, defaultPlan, CatalogDateHelper.toUTCDateTime(getEffectiveDate()), overrides.getOverrides(), internalCallContext);
}
@Override
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..b8f8fd0 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -226,17 +226,9 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
public void add(final StandaloneCatalog e) throws CatalogApiException {
if (catalogName == null) {
catalogName = e.getCatalogName();
- } else {
- if (!catalogName.equals(e.getCatalogName())) {
- throw new CatalogApiException(ErrorCode.CAT_CATALOG_NAME_MISMATCH, catalogName, e.getCatalogName());
- }
}
if (recurringBillingMode == null) {
recurringBillingMode = e.getRecurringBillingMode();
- } else {
- if (!recurringBillingMode.equals(e.getRecurringBillingMode())) {
- throw new CatalogApiException(ErrorCode.CAT_CATALOG_RECURRING_MODE_MISMATCH, recurringBillingMode, e.getRecurringBillingMode());
- }
}
versions.add(e);
Collections.sort(versions, new Comparator<StandaloneCatalog>() {
@@ -407,11 +399,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);
- }
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
}
@Override
@@ -428,7 +422,11 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
}
if (!c.getCatalogName().equals(catalogName)) {
errors.add(new ValidationError(String.format("Catalog name '%s' is not consistent across versions ", c.getCatalogName()),
- c.getCatalogURI(), VersionedCatalog.class, ""));
+ c.getCatalogURI(), VersionedCatalog.class, ""));
+ }
+ if (!c.getRecurringBillingMode().equals(recurringBillingMode)) {
+ errors.add(new ValidationError(String.format("Catalog recurringBillingMode '%s' is not consistent across versions ", c.getCatalogName()),
+ c.getCatalogURI(), VersionedCatalog.class, ""));
}
errors.addAll(c.validate(c, errors));
}
catalog/src/main/resources/EmptyCatalog.xml 10(+10 -0)
diff --git a/catalog/src/main/resources/EmptyCatalog.xml b/catalog/src/main/resources/EmptyCatalog.xml
index c3d9dff..679f928 100644
--- a/catalog/src/main/resources/EmptyCatalog.xml
+++ b/catalog/src/main/resources/EmptyCatalog.xml
@@ -35,6 +35,16 @@
</products>
<rules>
+ <changePolicy>
+ <changePolicyCase>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ </changePolicy>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
</rules>
<plans>
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockPlanPhase.java b/catalog/src/test/java/org/killbill/billing/catalog/MockPlanPhase.java
index 5ba79d3..b93df37 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockPlanPhase.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockPlanPhase.java
@@ -28,7 +28,7 @@ public class MockPlanPhase extends DefaultPlanPhase {
public static MockPlanPhase create1USDMonthlyEvergreen() {
return (MockPlanPhase) new MockPlanPhase(BillingPeriod.MONTHLY,
PhaseType.EVERGREEN,
- new DefaultDuration().setUnit(TimeUnit.UNLIMITED),
+ new DefaultDuration().setUnit(TimeUnit.UNLIMITED).setNumber(-1),
MockInternationalPrice.create1USD(),
null).setPlan(MockPlan.createBicycleNoTrialEvergreen1USD());
}
@@ -36,7 +36,7 @@ public class MockPlanPhase extends DefaultPlanPhase {
public static MockPlanPhase createUSDMonthlyEvergreen(final String reccuringUSDPrice, final String fixedPrice) {
return new MockPlanPhase(BillingPeriod.MONTHLY,
PhaseType.EVERGREEN,
- new DefaultDuration().setUnit(TimeUnit.UNLIMITED),
+ new DefaultDuration().setUnit(TimeUnit.UNLIMITED).setNumber(-1),
(reccuringUSDPrice == null) ? null : MockInternationalPrice.createUSD(reccuringUSDPrice),
(fixedPrice == null) ? null : MockInternationalPrice.createUSD(fixedPrice));
}
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogSafetyInitializer.java b/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogSafetyInitializer.java
index 26da112..18989ea 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogSafetyInitializer.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogSafetyInitializer.java
@@ -17,11 +17,14 @@
package org.killbill.billing.catalog;
+import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlIDREF;
+import org.killbill.billing.catalog.api.FixedType;
import org.killbill.billing.catalog.api.Product;
+import org.killbill.billing.catalog.api.TimeUnit;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -50,6 +53,20 @@ public class TestCatalogSafetyInitializer {
@XmlElement(type = DefaultProduct.class, name = "addonProduct", required = false)
private CatalogEntityCollection<Product> available;
+ @XmlElement(required = true)
+ private TimeUnit unit;
+
+ @XmlElement(required = false)
+ private Integer number;
+
+ @XmlElement(required = false)
+ private int smallNumber;
+
+ @XmlAttribute(required = false)
+ private FixedType type;
+
+
+
@Test(groups = "fast")
public void testNonRequiredArrayFields() {
@@ -60,7 +77,7 @@ public class TestCatalogSafetyInitializer {
Assert.assertNull(test.getPricesNotRequired());
Assert.assertNull(test.getPrices());
- CatalogSafetyInitializer.initializeNonRequiredArrayFields(test);
+ CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(test);
Assert.assertNull(test.getInitialPhasesWrapperAllRequired());
Assert.assertNotNull(test.getInitialPhasesWrapperNotRequired());
@@ -70,6 +87,13 @@ public class TestCatalogSafetyInitializer {
Assert.assertEquals(test.getPricesNotRequired().length, 0);
Assert.assertNull(test.getPrices());
+ Assert.assertNotNull(test.getNumber());
+ Assert.assertEquals(test.getNumber(), CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE);
+
+ Assert.assertNotNull(test.getSmallNumber());
+
+ Assert.assertNotNull(test.getType());
+ Assert.assertEquals(test.getType(), FixedType.ONE_TIME);
}
public DefaultPlanPhase[] getInitialPhasesWrapperAllRequired() {
@@ -92,4 +116,23 @@ public class TestCatalogSafetyInitializer {
return prices;
}
+ public CatalogEntityCollection<Product> getAvailable() {
+ return available;
+ }
+
+ public TimeUnit getUnit() {
+ return unit;
+ }
+
+ public Integer getNumber() {
+ return number;
+ }
+
+ public int getSmallNumber() {
+ return smallNumber;
+ }
+
+ public FixedType getType() {
+ return type;
+ }
}
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestDefaultPriceOverride.java b/catalog/src/test/java/org/killbill/billing/catalog/TestDefaultPriceOverride.java
index 278c67b..fb05299 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestDefaultPriceOverride.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestDefaultPriceOverride.java
@@ -25,7 +25,6 @@ import java.util.regex.Matcher;
import org.joda.time.DateTime;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Currency;
-import org.killbill.billing.catalog.api.CurrencyValueNull;
import org.killbill.billing.catalog.api.InternationalPrice;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
@@ -48,6 +47,7 @@ public class TestDefaultPriceOverride extends CatalogTestSuiteWithEmbeddedDB {
public void testBasic() throws Exception {
final StandaloneCatalog catalog = XMLLoader.getObjectFromString(Resources.getResource("SpyCarAdvanced.xml").toExternalForm(), StandaloneCatalog.class);
+ catalog.initialize(catalog, null);
final Plan plan = catalog.findCurrentPlan("discount-standard-monthly");
final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
@@ -56,7 +56,7 @@ public class TestDefaultPriceOverride extends CatalogTestSuiteWithEmbeddedDB {
final PlanPhasePriceOverride phase3 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[2].getName(), Currency.USD, null, new BigDecimal("142.41"));
overrides.add(phase3);
- final DefaultPlan overriddenPlan = priceOverride.getOrCreateOverriddenPlan(plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
+ final DefaultPlan overriddenPlan = priceOverride.getOrCreateOverriddenPlan(catalog, plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
final Matcher m = DefaultPriceOverride.CUSTOM_PLAN_NAME_PATTERN.matcher(overriddenPlan.getName());
assertTrue(m.matches());
@@ -101,13 +101,15 @@ public class TestDefaultPriceOverride extends CatalogTestSuiteWithEmbeddedDB {
public void testWithInvalidPriceOverride() throws Exception {
final StandaloneCatalog catalog = XMLLoader.getObjectFromString(Resources.getResource("SpyCarAdvanced.xml").toExternalForm(), StandaloneCatalog.class);
+ catalog.initialize(catalog, null);
+
final Plan plan = catalog.findCurrentPlan("discount-standard-monthly");
final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
final PlanPhasePriceOverride phase1 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, null, BigDecimal.ONE);
overrides.add(phase1);
- priceOverride.getOrCreateOverriddenPlan(plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
+ priceOverride.getOrCreateOverriddenPlan(catalog, plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
}
@@ -115,6 +117,8 @@ public class TestDefaultPriceOverride extends CatalogTestSuiteWithEmbeddedDB {
public void testGetOverriddenPlan() throws Exception {
final StandaloneCatalog catalog = XMLLoader.getObjectFromString(Resources.getResource("SpyCarAdvanced.xml").toExternalForm(), StandaloneCatalog.class);
+ catalog.initialize(catalog, null);
+
final Plan plan = catalog.findCurrentPlan("discount-standard-monthly");
final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
@@ -123,7 +127,7 @@ public class TestDefaultPriceOverride extends CatalogTestSuiteWithEmbeddedDB {
final PlanPhasePriceOverride phase3 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[2].getName(), Currency.USD, null, new BigDecimal("142.41"));
overrides.add(phase3);
- final DefaultPlan overriddenPlanCreated = priceOverride.getOrCreateOverriddenPlan(plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
+ final DefaultPlan overriddenPlanCreated = priceOverride.getOrCreateOverriddenPlan(catalog, plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
System.out.println("overriddenPlanCreated = " + overriddenPlanCreated.getName());
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestPlan.java b/catalog/src/test/java/org/killbill/billing/catalog/TestPlan.java
index 2f7cdaf..8e466cf 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestPlan.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestPlan.java
@@ -32,6 +32,7 @@ public class TestPlan extends CatalogTestSuiteNoDB {
final StandaloneCatalog c = new MockCatalog();
c.setSupportedCurrencies(new Currency[]{Currency.GBP, Currency.EUR, Currency.USD, Currency.BRL, Currency.MXN});
final DefaultPlan p1 = MockPlan.createBicycleTrialEvergreen1USD();
+ p1.setPlansAllowedInBundle(-1);
p1.setEffectiveDateForExistingSubscriptions(new Date((new Date().getTime()) - (1000 * 60 * 60 * 24)));
final ValidationErrors errors = p1.validate(c, new ValidationErrors());
Assert.assertEquals(errors.size(), 3);
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestStandaloneCatalog.java b/catalog/src/test/java/org/killbill/billing/catalog/TestStandaloneCatalog.java
index 32d839a..c7c411a 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestStandaloneCatalog.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestStandaloneCatalog.java
@@ -30,17 +30,26 @@ import com.google.common.io.Resources;
public class TestStandaloneCatalog extends CatalogTestSuiteNoDB {
@Test(groups = "fast")
- public void testLoadCatalogWithPlanInvalidProduct() throws Exception {
+ public void testLoadCatalogWithValidationIssues() throws Exception {
try {
XMLLoader.getObjectFromString(Resources.getResource("CatalogWithValidationErrors.xml").toExternalForm(), StandaloneCatalog.class);
Assert.fail();
} catch (final ValidationException e) {
- Assert.assertEquals(e.getErrors().size(), 5);
+ Assert.assertEquals(e.getErrors().size(), 13);
Assert.assertEquals(e.getErrors().get(0).getDescription(), "Invalid product for plan 'standard'");
Assert.assertEquals(e.getErrors().get(1).getDescription(), "Duration can only have 'UNLIMITED' unit if the number is omitted");
Assert.assertEquals(e.getErrors().get(2).getDescription(), "Finite Duration must have a well defined length");
Assert.assertEquals(e.getErrors().get(3).getDescription(), "Initial Phase standard-trial-evergreen of plan standard-trial cannot be of type EVERGREEN");
Assert.assertEquals(e.getErrors().get(4).getDescription(), "Final Phase standard-trial-trial of plan standard-trial cannot be of type TRIAL");
+ Assert.assertEquals(e.getErrors().get(5).getDescription(), "Duplicate rule for change plan DefaultCaseChangePlanPolicy {policy=IMMEDIATE, phaseType=null, fromProduct=DefaultProduct{name='Standard', category=BASE, included=org.killbill.billing.catalog.CatalogEntityCollection@0, available=org.killbill.billing.catalog.CatalogEntityCollection@0, limits=[], catalogName='CatalogWithValidationErrors'}, fromProductCategory=null, fromBillingPeriod=null, fromPriceList=null, toProduct=null, toProductCategory=null, toBillingPeriod=null, toPriceList=null}");
+ Assert.assertEquals(e.getErrors().get(6).getDescription(), "Missing default rule case for plan change");
+ Assert.assertEquals(e.getErrors().get(7).getDescription(), "Duplicate rule for plan cancellation DefaultCaseCancelPolicy{policy =IMMEDIATE, phaseType =null, product=DefaultProduct{name='Standard', category=BASE, included=org.killbill.billing.catalog.CatalogEntityCollection@0, available=org.killbill.billing.catalog.CatalogEntityCollection@0, limits=[], catalogName='CatalogWithValidationErrors'}, productCategory=null, billingPeriod=null, priceList=null}");
+ Assert.assertEquals(e.getErrors().get(8).getDescription(), "Missing default rule case for plan cancellation");
+ Assert.assertEquals(e.getErrors().get(9).getDescription(), "Duplicate rule for plan change alignment DefaultCaseChangePlanAlignment {alignment=START_OF_BUNDLE, phaseType=null, fromProduct=null, fromProductCategory=null, fromBillingPeriod=null, fromPriceList=null, toProduct=null, toProductCategory=null, toBillingPeriod=null, toPriceList=null}");
+ Assert.assertEquals(e.getErrors().get(10).getDescription(), "Duplicate rule for create plan alignment DefaultCaseCreateAlignment {alignment =START_OF_BUNDLE, product=null, productCategory=null, billingPeriod=null, priceList=null}");
+ Assert.assertEquals(e.getErrors().get(11).getDescription(), "Duplicate rule for billing alignment DefaultCaseBillingAlignment {alignment=ACCOUNT, phaseType=null, product=null, productCategory=null, billingPeriod=null, priceList=null}");
+ Assert.assertEquals(e.getErrors().get(12).getDescription(), "Duplicate rule for price list transition DefaultCasePriceList {fromProduct=null, fromProductCategory=null, fromBillingPeriod=null, fromPriceList=null, toPriceList=DefaultPriceList{name='DEFAULT}}");
+
}
}
diff --git a/catalog/src/test/resources/catalogTest.xml b/catalog/src/test/resources/catalogTest.xml
index 670abb5..8f28d1c 100644
--- a/catalog/src/test/resources/catalogTest.xml
+++ b/catalog/src/test/resources/catalogTest.xml
@@ -119,10 +119,6 @@
<policy>IMMEDIATE</policy>
</changePolicyCase>
<changePolicyCase>
- <toPriceList>rescue</toPriceList>
- <policy>END_OF_TERM</policy>
- </changePolicyCase>
- <changePolicyCase>
<fromBillingPeriod>MONTHLY</fromBillingPeriod>
<toBillingPeriod>ANNUAL</toBillingPeriod>
<policy>IMMEDIATE</policy>
diff --git a/catalog/src/test/resources/CatalogWithValidationErrors.xml b/catalog/src/test/resources/CatalogWithValidationErrors.xml
index 97cfb4d..26758f8 100644
--- a/catalog/src/test/resources/CatalogWithValidationErrors.xml
+++ b/catalog/src/test/resources/CatalogWithValidationErrors.xml
@@ -20,7 +20,7 @@
xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
<effectiveDate>2013-02-08T00:00:00+00:00</effectiveDate>
- <catalogName>CatalogWithPlanInvalidProduct</catalogName>
+ <catalogName>CatalogWithValidationErrors</catalogName>
<recurringBillingMode>IN_ADVANCE</recurringBillingMode>
@@ -34,7 +34,64 @@
</product>
</products>
- <rules></rules>
+
+
+ <!-- Note we defined twice the same rule for each case and also we miss default rules for plan cancellation and change of plan -->
+ <rules>
+ <changePolicy>
+ <changePolicyCase>
+ <fromProduct>Standard</fromProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromProduct>Standard</fromProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ </changePolicy>
+ <changeAlignment>
+ <changeAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </changeAlignmentCase>
+ <changeAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </changeAlignmentCase>
+ </changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <product>Standard</product>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ <cancelPolicyCase>
+ <product>Standard</product>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
+ <createAlignment>
+ <createAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </createAlignmentCase>
+ <createAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </createAlignmentCase>
+ </createAlignment>
+ <billingAlignment>
+ <billingAlignmentCase>
+ <alignment>ACCOUNT</alignment>
+ </billingAlignmentCase>
+ <billingAlignmentCase>
+ <alignment>ACCOUNT</alignment>
+ </billingAlignmentCase>
+ </billingAlignment>
+ <priceList>
+ <priceListCase>
+ <toPriceList>DEFAULT</toPriceList>
+ </priceListCase>
+ <priceListCase>
+ <toPriceList>DEFAULT</toPriceList>
+ </priceListCase>
+ </priceList>
+ </rules>
+
<plans>
<plan name="standard">
diff --git a/catalog/src/test/resources/UsageExperimental.xml b/catalog/src/test/resources/UsageExperimental.xml
index 11f3d17..4d2e7e9 100644
--- a/catalog/src/test/resources/UsageExperimental.xml
+++ b/catalog/src/test/resources/UsageExperimental.xml
@@ -62,10 +62,19 @@
</products>
<rules>
+ <changePolicy>
+ <changePolicyCase>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ </changePolicy>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
</rules>
<plans>
-
<plan name="capacity-in-advance-monthly">
<product>CapacityInAdvance</product>
<finalPhase type="EVERGREEN">
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
index b2b9276..f333572 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
@@ -68,12 +68,20 @@
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
+ <changePolicyCase>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
<alignment>START_OF_SUBSCRIPTION</alignment>
</changeAlignmentCase>
</changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
<createAlignment>
<createAlignmentCase>
<product>Laser-Scope</product>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
index f04ff0e..df1c09d 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
@@ -68,12 +68,20 @@
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
+ <changePolicyCase>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
<alignment>START_OF_SUBSCRIPTION</alignment>
</changeAlignmentCase>
</changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
<createAlignment>
<createAlignmentCase>
<product>Laser-Scope</product>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
index dc9c0b1..eb21229 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
@@ -68,12 +68,20 @@
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
+ <changePolicyCase>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
<alignment>START_OF_SUBSCRIPTION</alignment>
</changeAlignmentCase>
</changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
<createAlignment>
<createAlignmentCase>
<product>Laser-Scope</product>
diff --git a/catalog/src/test/resources/WeaponsHireSmall.xml b/catalog/src/test/resources/WeaponsHireSmall.xml
index 5adfb99..f64b5c6 100644
--- a/catalog/src/test/resources/WeaponsHireSmall.xml
+++ b/catalog/src/test/resources/WeaponsHireSmall.xml
@@ -68,12 +68,20 @@
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
+ <changePolicyCase>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
<alignment>START_OF_SUBSCRIPTION</alignment>
</changeAlignmentCase>
</changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
<createAlignment>
<createAlignmentCase>
<product>Laser-Scope</product>
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index d0a6be0..7e6042e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>org.kill-bill.billing</groupId>
- <version>0.140.5</version>
+ <version>0.140.6</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.18.2-SNAPSHOT</version>