killbill-uncached

Details

diff --git a/api/src/main/java/com/ning/billing/BillingExceptionBase.java b/api/src/main/java/com/ning/billing/BillingExceptionBase.java
index 486e5da..3a458fc 100644
--- a/api/src/main/java/com/ning/billing/BillingExceptionBase.java
+++ b/api/src/main/java/com/ning/billing/BillingExceptionBase.java
@@ -30,6 +30,12 @@ public class BillingExceptionBase extends Exception {
     private final int code;
     private final String formattedMsg;
 
+    public BillingExceptionBase(Throwable cause, int code, final String msg) {
+        this.formattedMsg = msg;
+        this.code = code;
+        this.cause = cause;
+    }
+
     public BillingExceptionBase(Throwable cause, ErrorCode code, final Object... args) {
         String tmp = null;
         try {
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApiException.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApiException.java
index c4b8c42..693938b 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApiException.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApiException.java
@@ -18,9 +18,15 @@ package com.ning.billing.entitlement.api.user;
 
 import com.ning.billing.BillingExceptionBase;
 import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
 
 public class EntitlementUserApiException extends BillingExceptionBase {
 
+    private static final long serialVersionUID = 19083233L;
+
+    public EntitlementUserApiException(CatalogApiException e) {
+        super(e, e.getCode(), e.getMessage());
+    }
     public EntitlementUserApiException(Throwable e, ErrorCode code, Object...args) {
         super(e, code, args);
     }
diff --git a/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java b/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java
index 21bf82a..4a64900 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java
@@ -17,6 +17,7 @@
 package com.ning.billing.catalog;
 
 import java.math.BigDecimal;
+import java.net.URI;
 import java.util.Date;
 
 import javax.xml.bind.annotation.XmlAccessType;
@@ -32,6 +33,8 @@ import com.ning.billing.util.config.ValidationErrors;
 @XmlAccessorType(XmlAccessType.NONE)
 public class InternationalPrice extends ValidatingConfig<Catalog> implements IInternationalPrice {
 
+	private static Price[] zeroPrice;
+
 	//TODO MDW Validation - effectiveDateForExistingSubscriptons > catalog effectiveDate 
 	@XmlElement(required=false)
 	private Date effectiveDateForExistingSubscriptons;
@@ -41,6 +44,7 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
 	@XmlElement(name="price")
 	private Price[] prices;
 
+
 	/* (non-Javadoc)
 	 * @see com.ning.billing.catalog.IInternationalPrice#getPrices()
 	 */
@@ -70,16 +74,8 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
 		}
 		return new BigDecimal(0);
 	}
-	
-	private boolean currencyIsSupported(Currency currency, Currency[] supportedCurrencies) {
-		for (Currency c : supportedCurrencies) {
-			if(c == currency) {
-				return true;
-			}
-		}
-		return false;
-	}
-	
+
+
 	protected void setEffectiveDateForExistingSubscriptons(
 			Date effectiveDateForExistingSubscriptons) {
 		this.effectiveDateForExistingSubscriptons = effectiveDateForExistingSubscriptons;
@@ -90,6 +86,29 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
 		return this;
 	}
 	
+
+
+	@Override
+	public void initialize(Catalog root, URI uri) {
+		if(prices == null) {
+			prices = getZeroPrice(root);
+		}
+		super.initialize(root, uri);
+	}
+	
+	private synchronized Price[] getZeroPrice(Catalog root) {
+		if(zeroPrice == null) {
+			Currency[] currencies = root.getSupportedCurrencies();
+			zeroPrice = new Price[currencies.length];
+			for(int i = 0; i < currencies.length; i++) {
+				prices[i] = new Price();
+				prices[i].setCurrency(currencies[i]);
+				prices[i].setValue(new BigDecimal(0));
+			}
+		}
+		return zeroPrice;
+	}
+
 	@Override
 	public ValidationErrors validate(Catalog catalog, ValidationErrors errors)  {
 		if(prices.length == 0) return errors;
@@ -103,7 +122,16 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
 		return errors;
 	}
 	
+	private boolean currencyIsSupported(Currency currency, Currency[] supportedCurrencies) {
+		for (Currency c : supportedCurrencies) {
+			if(c == currency) {
+				return true;
+			}
+		}
+		return false;
+	}
 	
 
 
+
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index afcf053..5280209 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -29,9 +29,13 @@ import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.ActionPolicy;
 import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.ICatalog;
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
+import com.ning.billing.catalog.api.IPriceList;
+import com.ning.billing.catalog.api.IProduct;
+import com.ning.billing.catalog.api.PlanChangeResult;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
@@ -257,7 +261,6 @@ public class Subscription extends PrivateFields  implements ISubscription {
             String priceList, DateTime requestedDate) throws EntitlementUserApiException {
 
         String currentPriceList = getCurrentPriceList();
-        String realPriceList = (priceList == null) ? currentPriceList : priceList;
 
         SubscriptionState currentState = getState();
         if (currentState != SubscriptionState.ACTIVE) {
@@ -269,30 +272,42 @@ public class Subscription extends PrivateFields  implements ISubscription {
         }
 
         DateTime now = clock.getUTCNow();
-        IPlan newPlan = catalog.getPlan(productName, term, realPriceList);
+        PlanChangeResult planChangeResult = null;
+        try {
+
+            IProduct destProduct = catalog.getProductFromName(productName);
+
+            IPlan currentPlan = getCurrentPlan();
+            PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+                    currentPlan.getProduct().getCategory(),
+                    currentPlan.getBillingPeriod(),
+                    currentPriceList, getCurrentPhase().getPhaseType());
+            PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
+                    destProduct.getCategory(),
+                    term,
+                    priceList);
+
+            planChangeResult = catalog.planChange(fromPlanPhase, toPlanPhase);
+        } catch (CatalogApiException e) {
+            throw new EntitlementUserApiException(e);
+        }
+
+        ActionPolicy policy = planChangeResult.getPolicy();
+        IPriceList newPriceList = planChangeResult.getNewPriceList();
+
+        IPlan newPlan = catalog.getPlan(productName, term, newPriceList.getName());
         if (newPlan == null) {
             throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_BAD_CATALOG,
-                    productName, term.toString(), realPriceList);
+                    productName, term.toString(), newPriceList.getName());
         }
 
-        IPlan currentPlan = getCurrentPlan();
-        PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-        		currentPlan.getProduct().getCategory(),
-                currentPlan.getBillingPeriod(),
-        		currentPriceList, getCurrentPhase().getPhaseType());
-        PlanSpecifier toPlanPhase = new PlanSpecifier(newPlan.getProduct().getName(),
-                newPlan.getProduct().getCategory(),
-        		newPlan.getBillingPeriod(),
-        		realPriceList);
-
-        ActionPolicy policy = catalog.getPlanChangePolicy(fromPlanPhase, toPlanPhase);
         DateTime effectiveDate = getPlanChangeEffectiveDate(policy, now);
 
-        TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(this, newPlan, realPriceList, effectiveDate);
+        TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(this, newPlan, newPriceList.getName(), effectiveDate);
         IEvent changeEvent = new ApiEventChange(id, bundleStartDate, now, newPlan.getName(), currentTimedPhase.getPhase().getName(),
-                realPriceList, now, effectiveDate, activeVersion);
+                newPriceList.getName(), now, effectiveDate, activeVersion);
 
-        TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(this, newPlan, realPriceList, effectiveDate);
+        TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(this, newPlan, newPriceList.getName(), effectiveDate);
         IPhaseEvent nextPhaseEvent = PhaseEvent.getNextPhaseEvent(nextTimedPhase, this, now);
         List<IEvent> changeEvents = new ArrayList<IEvent>();
         // Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.