killbill-aplcache

catalog: Add default initialization for non required `Double`

1/10/2017 10:32:29 PM

Details

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 68d90d8..c04bb98 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/CatalogSafetyInitializer.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/CatalogSafetyInitializer.java
@@ -33,6 +33,7 @@ public class CatalogSafetyInitializer {
 
 
     public static final Integer DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE = -1;
+    public static final Double DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE = new Double(-1);
 
     private static final Map<Class, LinkedList<Field>> perCatalogClassNonRequiredFields = new HashMap<Class, LinkedList<Field>>();
 
@@ -60,6 +61,8 @@ public class CatalogSafetyInitializer {
                         }
                     } else if (Integer.class.equals(f.getType())) {
                         initializeFieldWithValue(obj, f, DEFAULT_NON_REQUIRED_INTEGER_FIELD_VALUE);
+                    } else if (Double.class.equals(f.getType())) {
+                        initializeFieldWithValue(obj, f, DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE);
                     }
                 }
             }
@@ -97,6 +100,8 @@ public class CatalogSafetyInitializer {
                     }
                 } else if (Integer.class.equals(f.getType())) {
                     result.add(f);
+                } else if (Double.class.equals(f.getType())) {
+                    result.add(f);
                 }
             }
         }
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 6604384..a7dd99b 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java
@@ -17,6 +17,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.XmlAttribute;
@@ -78,7 +80,7 @@ public class DefaultBlock extends ValidatingConfig<StandaloneCatalog> implements
 
     @Override
     public Double getMinTopUpCredit() throws CatalogApiException {
-        if (minTopUpCredit != null && type != BlockType.TOP_UP) {
+        if (minTopUpCredit != CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE && type != BlockType.TOP_UP) {
             throw new CatalogApiException(ErrorCode.CAT_NOT_TOP_UP_BLOCK, phase.getName());
         }
         return minTopUpCredit;
@@ -91,13 +93,20 @@ public class DefaultBlock extends ValidatingConfig<StandaloneCatalog> implements
             throw new IllegalStateException("type should have been automatically been initialized with VANILLA ");
         }
 
-        if (type == BlockType.TOP_UP && minTopUpCredit == null) {
+        if (type == BlockType.TOP_UP && minTopUpCredit == CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE) {
             errors.add(new ValidationError(String.format("TOP_UP block needs to define minTopUpCredit for phase %s",
                                                          phase.getName()), catalog.getCatalogURI(), DefaultUsage.class, ""));
         }
         return errors;
     }
 
+    @Override
+    public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
+        super.initialize(catalog, sourceURI);
+        CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
+    }
+
+
     public DefaultBlock setType(final BlockType type) {
         this.type = type;
         return 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 30176b5..b594c03 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultLimit.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultLimit.java
@@ -69,12 +69,13 @@ public class DefaultLimit extends ValidatingConfig<StandaloneCatalog> implements
 
     @Override
     public ValidationErrors validate(StandaloneCatalog root, ValidationErrors errors) {
-        if (max == null && min == null) {
+        if (max == CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE && min == CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE) {
             errors.add(new ValidationError("max and min cannot both be ommitted", root.getCatalogURI(), Limit.class, ""));
-        } else if (max != null && min != null && max.doubleValue() < min.doubleValue()) {
+        } else if (max != CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE &&
+                   min != CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE &&
+                   max.doubleValue() < min.doubleValue()) {
             errors.add(new ValidationError("max must be greater than min", root.getCatalogURI(), Limit.class, ""));
         }
-
         return errors;
     }
 
@@ -87,12 +88,12 @@ public class DefaultLimit extends ValidatingConfig<StandaloneCatalog> implements
 
     @Override
     public boolean compliesWith(double value) {
-        if (max != null) {
+        if (max != CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE) {
             if (value > max.doubleValue()) {
                 return false;
             }
         }
-        if (min != null) {
+        if (min != CatalogSafetyInitializer.DEFAULT_NON_REQUIRED_DOUBLE_FIELD_VALUE) {
             if (value < min.doubleValue()) {
                 return false;
             }
@@ -126,10 +127,10 @@ public class DefaultLimit extends ValidatingConfig<StandaloneCatalog> implements
 
         final DefaultLimit that = (DefaultLimit) o;
 
-        if (max != null ? !max.equals(that.max) : that.max != null) {
+        if (!max.equals(that.max)) {
             return false;
         }
-        if (min != null ? !min.equals(that.min) : that.min != null) {
+        if (!min.equals(that.min)) {
             return false;
         }
         if (unit != null ? !unit.equals(that.unit) : that.unit != null) {
@@ -142,8 +143,8 @@ public class DefaultLimit extends ValidatingConfig<StandaloneCatalog> implements
     @Override
     public int hashCode() {
         int result = unit != null ? unit.hashCode() : 0;
-        result = 31 * result + (max != null ? max.hashCode() : 0);
-        result = 31 * result + (min != null ? min.hashCode() : 0);
+        result = 31 * result + max.hashCode();
+        result = 31 * result + min.hashCode();
         return result;
     }
 }
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 21ad681..9b205c0 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java
@@ -134,6 +134,12 @@ public class DefaultTier extends ValidatingConfig<StandaloneCatalog> implements 
     public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
         super.initialize(catalog, sourceURI);
         CatalogSafetyInitializer.initializeNonRequiredNullFieldsWithDefaultValue(this);
+        for (DefaultLimit cur : limits) {
+            cur.initialize(catalog, sourceURI);
+        }
+        for (DefaultBlock cur : blocks) {
+            cur.initialize(catalog, sourceURI);
+        }
     }
 
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
index d7ab1b3..25ce0f3 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
@@ -61,6 +61,15 @@ public class TestCatalog extends TestJaxrsBase {
     }
 
     @Test(groups = "slow")
+    public void testUploadAndFetchUsageCatlog() throws Exception {
+        final String versionPath1 = Resources.getResource("UsageExperimental.xml").getPath();
+        killBillClient.uploadXMLCatalog(versionPath1, requestOptions);
+        String catalog = killBillClient.getXMLCatalog(requestOptions);
+        Assert.assertNotNull(catalog);
+    }
+
+
+    @Test(groups = "slow")
     public void testUploadWithErrors() throws Exception {
         final String versionPath1 = Resources.getResource("SpyCarBasic.xml").getPath();
         killBillClient.uploadXMLCatalog(versionPath1, requestOptions);
diff --git a/profiles/killbill/src/test/resources/UsageExperimental.xml b/profiles/killbill/src/test/resources/UsageExperimental.xml
new file mode 100644
index 0000000..4d2e7e9
--- /dev/null
+++ b/profiles/killbill/src/test/resources/UsageExperimental.xml
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ Copyright 2014 The Billing Project, Inc.
+  ~
+  ~ Ning 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>Usage</catalogName>
+
+    <!-- TBD
+    Defines the billingMode for all recurring subscription in that catalog:
+    Goal is to avoid to end up in a situation where a user could switch plan and suddenly his
+    recurring billing goes from IN_ADVANCE to IN_ARREAR or the reverse.
+    -->
+    <recurringBillingMode>IN_ADVANCE</recurringBillingMode>
+
+    <currencies>
+        <currency>BTC</currency>
+    </currencies>
+
+    <units>
+        <unit name="members"/>
+        <unit name="cell-phone-minutes"/>
+        <unit name="fastrack-tokens"/>
+        <unit name="bandwith-meg-sec"/>
+        <unit name="Mbytes"/>
+    </units>
+
+    <products>
+        <product name="Dummy">
+            <category>BASE</category>
+        </product>
+        <product name="CapacityInAdvance">
+            <category>BASE</category>
+        </product>
+        <product name="ConsumableInAdvancePrepayCredit">
+            <category>BASE</category>
+        </product>
+        <product name="ConsumableInAdvanceTopUp">
+            <category>BASE</category>
+        </product>
+        <product name="CapacityInArrear">
+            <category>BASE</category>
+        </product>
+        <product name="ConsumableInArrear">
+            <category>BASE</category>
+        </product>
+    </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">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+
+                <usages>
+                    <usage name="capacity-in-advance-monthly-usage1" billingMode="IN_ADVANCE" usageType="CAPACITY">
+                        <billingPeriod>MONTHLY</billingPeriod>
+                        <limits>
+                            <limit>
+                                <unit>members</unit>
+                                <max>100</max>
+                            </limit>
+                        </limits>
+                        <!-- could accept a fixed price and/or a recurring price -->
+                        <recurringPrice>
+                            <price>
+                                <currency>BTC</currency>
+                                <value>100.00</value>
+                            </price>
+                        </recurringPrice>
+                    </usage>
+                </usages>
+            </finalPhase>
+        </plan>
+
+
+        <plan name="consumable-in-advance-prepay-credit-monthly">
+            <product>ConsumableInAdvancePrepayCredit</product>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+                <usages>
+                    <usage name="consumable-in-advance-prepay-credit-monthly-usage1" billingMode="IN_ADVANCE" usageType="CONSUMABLE">
+                        <billingPeriod>MONTHLY</billingPeriod>
+                        <blocks>
+                            <block>
+                                <unit>cell-phone-minutes</unit>
+                                <size>1000</size>
+                                <!-- could be either fixed (with NO_BILLING_PERIOD) )or recurring:
+                                * In billing period is NO_BILLING_PERIOD, we buy one block of units
+                                * In billing period ha s been specified, we buy one block of units for each period
+                                -->
+                                <prices>
+                                    <price>
+                                        <currency>BTC</currency>
+                                        <value>0.10</value>
+                                    </price>
+                                </prices>
+                            </block>
+                        </blocks>
+                        <!-- We could instead define the price here as we did for capacity-in-advance if we want to 'bundle' linit/units -->
+                    </usage>
+                </usages>
+            </finalPhase>
+        </plan>
+
+
+        <plan name="consumable-in-advance-topup">
+            <product>ConsumableInAdvanceTopUp</product>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+
+                <usages>
+                    <usage name="consumable-in-advance-topup-usage1" billingMode="IN_ADVANCE" usageType="CONSUMABLE">
+                        <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+                        <blocks>
+                            <block type="TOP_UP">
+                                <unit>fastrack-tokens</unit>
+                                <size>10</size>
+                                <prices>
+                                    <price>
+                                        <currency>BTC</currency>
+                                        <value>0.10</value>
+                                    </price>
+                                </prices>
+                                <minTopUpCredit>5</minTopUpCredit>
+                            </block>
+                        </blocks>
+                    </usage>
+                </usages>
+            </finalPhase>
+        </plan>
+
+
+        <plan name="capacity-in-arrear">
+            <product>CapacityInArrear</product>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+
+                <usages>
+                    <usage name="capacity-in-arrear-usage1" billingMode="IN_ARREAR" usageType="CAPACITY">
+                        <billingPeriod>MONTHLY</billingPeriod>
+                        <tiers>
+                            <tier>
+                                <limits>
+                                    <limit>
+                                        <unit>bandwith-meg-sec</unit>
+                                        <max>100</max>
+                                    </limit>
+                                    <limit>
+                                        <unit>members</unit>
+                                        <max>500</max>
+                                    </limit>
+                                </limits>
+                                <fixedPrice>
+                                    <price>
+                                        <currency>BTC</currency>
+                                        <value>0.007</value>
+                                    </price>
+                                </fixedPrice>
+                                <recurringPrice>
+                                    <price>
+                                        <currency>BTC</currency>
+                                        <value>0.8</value>
+                                    </price>
+                                </recurringPrice>
+                            </tier>
+                            <tier>
+                                <limits>
+                                    <limit>
+                                        <unit>bandwith-meg-sec</unit>
+                                        <max>100</max>
+                                    </limit>
+                                    <limit>
+                                        <unit>members</unit>
+                                        <max>1000</max>
+                                    </limit>
+                                </limits>
+                                <fixedPrice>
+                                    <price>
+                                        <currency>BTC</currency>
+                                        <value>0.4</value>
+                                    </price>
+                                </fixedPrice>
+                                <recurringPrice>
+                                    <price>
+                                        <currency>BTC</currency>
+                                        <value>1.2</value>
+                                    </price>
+                                </recurringPrice>
+                            </tier>
+                        </tiers>
+                    </usage>
+                </usages>
+            </finalPhase>
+        </plan>
+
+
+        <plan name="consumable-in-arrear">
+            <product>ConsumableInArrear</product>
+            <finalPhase type="EVERGREEN">
+                <duration>
+                    <unit>UNLIMITED</unit>
+                </duration>
+                <usages>
+                    <usage name="consumable-in-arrear-usage1" billingMode="IN_ARREAR" usageType="CONSUMABLE">
+                        <billingPeriod>MONTHLY</billingPeriod>
+                        <tiers>
+                            <tier>
+                                <blocks>
+                                    <tieredBlock>
+                                        <unit>cell-phone-minutes</unit>
+                                        <size>1000</size>
+                                        <prices>
+                                            <price>
+                                                <currency>BTC</currency>
+                                                <value>0.5</value>
+                                            </price>
+                                        </prices>
+                                        <max>10000</max>
+                                    </tieredBlock>
+                                    <tieredBlock>
+                                        <unit>Mbytes</unit>
+                                        <size>512</size>
+                                        <prices>
+                                            <price>
+                                                <currency>BTC</currency>
+                                                <value>0.3</value>
+                                            </price>
+                                        </prices>
+                                        <max>512000</max>
+                                    </tieredBlock>
+                                </blocks>
+                            </tier>
+                        </tiers>
+                    </usage>
+                </usages>
+            </finalPhase>
+        </plan>
+
+
+    </plans>
+    <priceLists>
+        <defaultPriceList name="DEFAULT">
+            <plans>
+                <plan>capacity-in-advance-monthly</plan>
+                <plan>consumable-in-advance-prepay-credit-monthly</plan>
+                <plan>consumable-in-advance-topup</plan>
+                <plan>capacity-in-arrear</plan>
+                <plan>consumable-in-arrear</plan>
+            </plans>
+        </defaultPriceList>
+    </priceLists>
+</catalog>