killbill-memoizeit

Fixes #234 Initial implementation for #236 Changes catalog

12/16/2014 6:20:24 PM

Changes

jaxrs/pom.xml 4(+4 -0)

Details

diff --git a/api/src/main/java/org/killbill/billing/catalog/api/CatalogService.java b/api/src/main/java/org/killbill/billing/catalog/api/CatalogService.java
index d250244..a5f7e6c 100644
--- a/api/src/main/java/org/killbill/billing/catalog/api/CatalogService.java
+++ b/api/src/main/java/org/killbill/billing/catalog/api/CatalogService.java
@@ -18,15 +18,17 @@
 
 package org.killbill.billing.catalog.api;
 
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.platform.api.KillbillService;
+import org.killbill.billing.util.callcontext.TenantContext;
 
 /**
  * The interface {@code CatalogService} is a {@code KillbillService} required to handle catalog operations.
  */
 public interface CatalogService extends KillbillService {
 
-    public abstract Catalog getFullCatalog();
+    public abstract Catalog getFullCatalog(InternalTenantContext context) throws CatalogApiException;
 
-    public abstract StaticCatalog getCurrentCatalog();
+    public abstract StaticCatalog getCurrentCatalog(InternalTenantContext context) throws CatalogApiException;
 
 }
diff --git a/api/src/main/java/org/killbill/billing/glue/TenantModule.java b/api/src/main/java/org/killbill/billing/glue/TenantModule.java
new file mode 100644
index 0000000..b240701
--- /dev/null
+++ b/api/src/main/java/org/killbill/billing/glue/TenantModule.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.glue;
+
+public interface TenantModule {
+
+    public void installTenantUserApi();
+
+    public void installTenantService();
+}
diff --git a/api/src/main/java/org/killbill/billing/junction/BillingInternalApi.java b/api/src/main/java/org/killbill/billing/junction/BillingInternalApi.java
index 0f9e8fa..f6ea2cd 100644
--- a/api/src/main/java/org/killbill/billing/junction/BillingInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/junction/BillingInternalApi.java
@@ -19,6 +19,7 @@ package org.killbill.billing.junction;
 import java.util.UUID;
 
 import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.invoice.api.DryRunArguments;
 
 public interface BillingInternalApi {
@@ -26,5 +27,5 @@ public interface BillingInternalApi {
     /**
      * @return an ordered list of billing event for the given accounts
      */
-    public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(UUID accountId, DryRunArguments dryRunArguments, InternalCallContext context);
+    public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(UUID accountId, DryRunArguments dryRunArguments, InternalCallContext context) throws CatalogApiException;
 }
diff --git a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
index 245f81a..44b315d 100644
--- a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
@@ -58,7 +58,7 @@ public interface SubscriptionBaseInternalApi {
     public List<SubscriptionBase> getSubscriptionsForBundle(UUID bundleId, DryRunArguments dryRunArguments, InternalTenantContext context)
             throws SubscriptionBaseApiException;
 
-    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(InternalTenantContext context);
+    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(InternalTenantContext context) throws SubscriptionBaseApiException;
 
     public SubscriptionBase getBaseSubscription(UUID bundleId, InternalTenantContext context) throws SubscriptionBaseApiException;
 
@@ -68,7 +68,7 @@ public interface SubscriptionBaseInternalApi {
 
     public UUID getAccountIdFromSubscriptionId(UUID subscriptionId, InternalTenantContext context) throws SubscriptionBaseApiException;
 
-    public void setChargedThroughDate(UUID subscriptionId, DateTime chargedThruDate, InternalCallContext context);
+    public void setChargedThroughDate(UUID subscriptionId, DateTime chargedThruDate, InternalCallContext context) throws SubscriptionBaseApiException;
 
     public List<EffectiveSubscriptionInternalEvent> getAllTransitions(SubscriptionBase subscription, InternalTenantContext context);
 
diff --git a/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java b/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java
new file mode 100644
index 0000000..08ca044
--- /dev/null
+++ b/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.tenant.api;
+
+import java.util.List;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+
+public interface TenantInternalApi {
+    List<String> getTenantCatalogs(InternalTenantContext tenantContext) throws TenantApiException;
+}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModule.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModule.java
index 9bb038e..0817d1d 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModule.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModule.java
@@ -41,7 +41,7 @@ import org.killbill.billing.payment.glue.PaymentModule;
 import org.killbill.billing.payment.provider.MockPaymentProviderPluginModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.subscription.glue.DefaultSubscriptionModule;
-import org.killbill.billing.tenant.glue.TenantModule;
+import org.killbill.billing.tenant.glue.DefaultTenantModule;
 import org.killbill.billing.usage.glue.UsageModule;
 import org.killbill.billing.util.config.PaymentConfig;
 import org.killbill.billing.util.email.EmailModule;
@@ -90,7 +90,7 @@ public class BeatrixIntegrationModule extends KillBillModule {
         install(new IntegrationTestOverdueModule(configSource));
         install(new AuditModule(configSource));
         install(new CurrencyModule(configSource));
-        install(new TenantModule(configSource));
+        install(new DefaultTenantModule(configSource));
         install(new ExportModule(configSource));
         install(new NonEntityDaoModule(configSource));
         install(new RecordIdModule(configSource));
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 04368ba..41a1638 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
@@ -18,24 +18,35 @@ package org.killbill.billing.catalog.api.user;
 
 import javax.inject.Inject;
 
+import org.killbill.billing.callcontext.InternalTenantContext;
 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.StaticCatalog;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
 
 public class DefaultCatalogUserApi implements CatalogUserApi {
 
     private final CatalogService catalogService;
+    private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
-    public DefaultCatalogUserApi(final CatalogService catalogService) {
+    public DefaultCatalogUserApi(final CatalogService catalogService, final InternalCallContextFactory internalCallContextFactory) {
         this.catalogService = catalogService;
+        this.internalCallContextFactory = internalCallContextFactory;
     }
 
     @Override
-    public Catalog getCatalog(final String catalogName, final TenantContext context) {
-        // STEPH TODO this is  hack until we decides what do do exactly:
-        // Probably we want one catalog for tenant but but TBD
-        return catalogService.getFullCatalog();
+    public Catalog getCatalog(final String catalogName, final TenantContext tenantContext) throws CatalogApiException {
+        final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantContext);
+        return catalogService.getFullCatalog(internalTenantContext);
+    }
+
+    @Override
+    public StaticCatalog getCurrentCatalog(final String catalogName, final TenantContext tenantContext) throws CatalogApiException {
+        final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantContext);
+        return catalogService.getCurrentCatalog(internalTenantContext);
     }
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultCatalogService.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultCatalogService.java
index c9650fe..193f4db 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultCatalogService.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultCatalogService.java
@@ -18,19 +18,30 @@
 
 package org.killbill.billing.catalog;
 
+import java.util.List;
+
+import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalTenantContext;
 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.StaticCatalog;
 import org.killbill.billing.catalog.io.VersionedCatalogLoader;
 import org.killbill.billing.platform.api.KillbillService;
 import org.killbill.billing.platform.api.LifecycleHandlerType;
 import org.killbill.billing.platform.api.LifecycleHandlerType.LifecycleLevel;
+import org.killbill.billing.tenant.api.TenantApiException;
+import org.killbill.billing.tenant.api.TenantInternalApi;
+import org.killbill.billing.tenant.api.TenantKV.TenantKey;
+import org.killbill.billing.tenant.api.TenantUserApi;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.billing.util.config.CatalogConfig;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
-public class DefaultCatalogService implements KillbillService, Provider<Catalog>, CatalogService {
+public class DefaultCatalogService implements KillbillService, CatalogService {
 
     private static final String CATALOG_SERVICE_NAME = "catalog-service";
 
@@ -40,12 +51,15 @@ public class DefaultCatalogService implements KillbillService, Provider<Catalog>
     private boolean isInitialized;
 
     private final VersionedCatalogLoader loader;
+    private final TenantInternalApi tenantApi;
 
     @Inject
-    public DefaultCatalogService(final CatalogConfig config, final VersionedCatalogLoader loader) {
+    public DefaultCatalogService(final CatalogConfig config, final TenantInternalApi tenantApi, final VersionedCatalogLoader loader) {
         this.config = config;
         this.isInitialized = false;
         this.loader = loader;
+        this.tenantApi = tenantApi;
+
     }
 
     @LifecycleHandlerType(LifecycleLevel.LOAD_CATALOG)
@@ -54,7 +68,6 @@ public class DefaultCatalogService implements KillbillService, Provider<Catalog>
             try {
                 final String url = config.getCatalogURI();
                 catalog = loader.load(url);
-
                 isInitialized = true;
             } catch (Exception e) {
                 throw new ServiceException(e);
@@ -68,17 +81,30 @@ public class DefaultCatalogService implements KillbillService, Provider<Catalog>
     }
 
     @Override
-    public Catalog getFullCatalog() {
-        return catalog;
+    public Catalog getFullCatalog(final InternalTenantContext context) throws CatalogApiException {
+        return getCatalog(context);
     }
 
     @Override
-    public Catalog get() {
-        return catalog;
+    public StaticCatalog getCurrentCatalog(final InternalTenantContext context) throws CatalogApiException {
+        return getCatalog(context);
     }
 
-    @Override
-    public StaticCatalog getCurrentCatalog() {
-        return catalog;
+    private VersionedCatalog getCatalog(final InternalTenantContext context) throws CatalogApiException {
+        if (context.getTenantRecordId() == InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID) {
+            return catalog;
+        }
+        try {
+            final List<String> catalogXMLs = tenantApi.getTenantCatalogs(context);
+            if (catalogXMLs.isEmpty()) {
+                return catalog;
+            }
+            return loader.load(catalogXMLs);
+        } catch (TenantApiException e) {
+            throw new CatalogApiException(e);
+        } catch (ServiceException e) {
+            throw new CatalogApiException(ErrorCode.CAT_INVALID_FOR_TENANT, "Failed to load catalog for tenant " + context.getTenantRecordId());
+        }
     }
+
 }
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 e2087fc..c45cb40 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
@@ -16,20 +16,30 @@
 
 package org.killbill.billing.catalog.io;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.xml.bind.JAXBException;
+import javax.xml.transform.TransformerException;
+
 import com.google.common.io.Resources;
 import com.google.inject.Inject;
 import org.killbill.billing.catalog.StandaloneCatalog;
 import org.killbill.billing.catalog.VersionedCatalog;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.InvalidConfigException;
 import org.killbill.billing.platform.api.KillbillService.ServiceException;
 import org.killbill.clock.Clock;
 import org.killbill.xmlloader.UriAccessor;
+import org.killbill.xmlloader.ValidationException;
 import org.killbill.xmlloader.XMLLoader;
+import org.xml.sax.SAXException;
 
 public class VersionedCatalogLoader implements ICatalogLoader {
     private static final Object PROTOCOL_FOR_FILE = "file";
@@ -82,6 +92,22 @@ public class VersionedCatalogLoader implements ICatalogLoader {
         }
     }
 
+    public VersionedCatalog load(final List<String> catalogXMLs) throws ServiceException {
+        final VersionedCatalog result = new VersionedCatalog(clock);
+        final URI uri;
+        try {
+            uri = new URI("/tenantCatalog");
+            for (final String cur : catalogXMLs) {
+                final InputStream curCatalogStream = new ByteArrayInputStream(cur.getBytes());
+                final StandaloneCatalog catalog = XMLLoader.getObjectFromStream(uri, curCatalogStream, StandaloneCatalog.class);
+                result.add(catalog);
+            }
+            return result;
+        } catch (Exception e) {
+            throw new ServiceException("Problem encountered loading catalog", e);
+        }
+    }
+
     protected List<URI> findXmlReferences(final String directoryContents, final URL url) throws URISyntaxException {
         if (url.getProtocol().equals(PROTOCOL_FOR_FILE)) {
             return findXmlFileReferences(directoryContents, url);
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 a06048a..d0ff756 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -68,10 +68,16 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
     @XmlElement(name = "catalogVersion", required = true)
     private final List<StandaloneCatalog> versions = new ArrayList<StandaloneCatalog>();
 
+    // Default CTOR for XMLWriter.writeXML
+    public VersionedCatalog() {
+        this.clock = null;
+    }
+
     public VersionedCatalog(final Clock clock) {
         this.clock = clock;
     }
 
+
     //
     // Private methods
     //
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/glue/TestCatalogModule.java b/catalog/src/test/java/org/killbill/billing/catalog/glue/TestCatalogModule.java
index 590ca2c..9af00a4 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/glue/TestCatalogModule.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/glue/TestCatalogModule.java
@@ -19,7 +19,10 @@
 package org.killbill.billing.catalog.glue;
 
 import org.killbill.billing.GuicyKillbillTestNoDBModule;
+import org.killbill.billing.mock.glue.MockNonEntityDaoModule;
+import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.util.glue.CacheModule;
 
 public class TestCatalogModule extends CatalogModule {
 
@@ -31,5 +34,8 @@ public class TestCatalogModule extends CatalogModule {
     public void configure() {
         super.configure();
         install(new GuicyKillbillTestNoDBModule(configSource));
+        install(new MockNonEntityDaoModule(configSource));
+        install(new CacheModule(configSource));
+        install(new MockTenantModule(configSource));
     }
 }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogModule.java b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogModule.java
index ada9dd4..f74e9de 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogModule.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogModule.java
@@ -18,7 +18,9 @@
 
 package org.killbill.billing.catalog;
 
+import org.killbill.billing.callcontext.InternalCallContext;
 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.platform.api.KillbillConfigSource;
 import org.killbill.billing.util.glue.KillBillModule;
@@ -35,8 +37,12 @@ public class MockCatalogModule extends KillBillModule {
         final Catalog catalog = Mockito.mock(Catalog.class);
 
         final CatalogService catalogService = Mockito.mock(CatalogService.class);
-        Mockito.when(catalogService.getCurrentCatalog()).thenReturn(new MockCatalog());
-        Mockito.when(catalogService.getFullCatalog()).thenReturn(catalog);
-        bind(CatalogService.class).toInstance(catalogService);
+        try {
+            Mockito.when(catalogService.getCurrentCatalog(Mockito.any(InternalCallContext.class))).thenReturn(new MockCatalog());
+            Mockito.when(catalogService.getFullCatalog(Mockito.any(InternalCallContext.class))).thenReturn(catalog);
+            bind(CatalogService.class).toInstance(catalogService);
+        } catch (CatalogApiException e) {
+            throw new RuntimeException(e);
+        }
     }
 }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogService.java b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogService.java
index bf38751..f5e4dc5 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogService.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogService.java
@@ -16,6 +16,7 @@
 
 package org.killbill.billing.catalog;
 
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.StaticCatalog;
 
@@ -24,7 +25,7 @@ public class MockCatalogService extends DefaultCatalogService {
     private final MockCatalog catalog;
 
     public MockCatalogService(final MockCatalog catalog) {
-        super(null, null);
+        super(null, null, null);
         this.catalog = catalog;
     }
 
@@ -38,19 +39,13 @@ public class MockCatalogService extends DefaultCatalogService {
     }
 
     @Override
-    public Catalog getFullCatalog() {
+    public Catalog getFullCatalog(InternalTenantContext context) {
         return catalog;
     }
 
     @Override
-    public Catalog get() {
+    public StaticCatalog getCurrentCatalog(InternalTenantContext context) {
         return catalog;
     }
 
-    @Override
-    public StaticCatalog getCurrentCatalog() {
-        return catalog;
-    }
-
-
 }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogService.java b/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogService.java
index 3845f7b..95336cc 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogService.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogService.java
@@ -18,6 +18,7 @@
 
 package org.killbill.billing.catalog;
 
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.io.VersionedCatalogLoader;
 import org.killbill.billing.platform.api.KillbillService.ServiceException;
 import org.killbill.billing.util.config.CatalogConfig;
@@ -28,30 +29,30 @@ import org.testng.annotations.Test;
 public class TestCatalogService extends CatalogTestSuiteNoDB {
 
     @Test(groups = "fast")
-    public void testCatalogServiceDirectory() throws ServiceException {
+    public void testCatalogServiceDirectory() throws ServiceException, CatalogApiException {
         final DefaultCatalogService service = new DefaultCatalogService(new CatalogConfig() {
             @Override
             public String getCatalogURI() {
                 return "file:src/test/resources/versionedCatalog";
             }
 
-        }, new VersionedCatalogLoader(new DefaultClock()));
+        }, null,  new VersionedCatalogLoader(new DefaultClock()));
         service.loadCatalog();
-        Assert.assertNotNull(service.getFullCatalog());
-        Assert.assertEquals(service.getFullCatalog().getCatalogName(), "WeaponsHireSmall");
+        Assert.assertNotNull(service.getFullCatalog(internalCallContext));
+        Assert.assertEquals(service.getFullCatalog(internalCallContext).getCatalogName(), "WeaponsHireSmall");
     }
 
     @Test(groups = "fast")
-    public void testCatalogServiceFile() throws ServiceException {
+    public void testCatalogServiceFile() throws ServiceException, CatalogApiException {
         final DefaultCatalogService service = new DefaultCatalogService(new CatalogConfig() {
             @Override
             public String getCatalogURI() {
                 return "file:src/test/resources/WeaponsHire.xml";
             }
 
-        }, new VersionedCatalogLoader(new DefaultClock()));
+        }, null, new VersionedCatalogLoader(new DefaultClock()));
         service.loadCatalog();
-        Assert.assertNotNull(service.getFullCatalog());
-        Assert.assertEquals(service.getFullCatalog().getCatalogName(), "Firearms");
+        Assert.assertNotNull(service.getFullCatalog(internalCallContext));
+        Assert.assertEquals(service.getFullCatalog(internalCallContext).getCatalogName(), "Firearms");
     }
 }
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java
index 8bd83ff..b326690 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java
@@ -29,6 +29,7 @@ import javax.inject.Inject;
 import javax.inject.Singleton;
 
 import org.joda.time.DateTime;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -278,6 +279,9 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
         } catch (EntitlementApiException e) {
             log.error("Error computing blocking states for addons for account record id " + context.getAccountRecordId(), e);
             throw new RuntimeException(e);
+        } catch (SubscriptionBaseApiException e) {
+            log.error("Error computing blocking states for addons for account record id " + context.getAccountRecordId(), e);
+            throw new RuntimeException(e);
         }
 
         return addBlockingStatesNotOnDisk(null, null, blockingStatesOnDiskCopy, baseSubscriptionsToConsider, eventsStreams);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
index 835fd6c..ba71e6f 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
@@ -111,8 +111,13 @@ public class EventsStreamBuilder {
 
     public AccountEventsStreams buildForAccount(final InternalTenantContext internalTenantContext) throws EntitlementApiException {
         // Retrieve the subscriptions (map bundle id -> subscriptions)
-        final Map<UUID, List<SubscriptionBase>> subscriptions = subscriptionInternalApi.getSubscriptionsForAccount(internalTenantContext);
-        return buildForAccount(subscriptions, internalTenantContext);
+        final Map<UUID, List<SubscriptionBase>> subscriptions;
+        try {
+            subscriptions = subscriptionInternalApi.getSubscriptionsForAccount(internalTenantContext);
+            return buildForAccount(subscriptions, internalTenantContext);
+        } catch (SubscriptionBaseApiException e) {
+            throw new EntitlementApiException(e);
+        }
     }
 
     // Special signature for ProxyBlockingStateDao to save a DAO call
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
index adde561..f6e459a 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
@@ -18,6 +18,7 @@ package org.killbill.billing.entitlement.api;
 
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.testng.annotations.Test;
 
 import org.killbill.billing.account.api.Account;
@@ -155,7 +156,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testCancelWithEntitlementPolicyIMMAndCTD() throws AccountApiException, EntitlementApiException, SubscriptionApiException {
+    public void testCancelWithEntitlementPolicyIMMAndCTD() throws AccountApiException, EntitlementApiException, SubscriptionApiException, SubscriptionBaseApiException {
         final LocalDate initialDate = new LocalDate(2013, 8, 7);
         clock.setDay(initialDate);
 
@@ -198,7 +199,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testCancelWithEntitlementPolicyEOTAndCTD() throws AccountApiException, EntitlementApiException, SubscriptionApiException {
+    public void testCancelWithEntitlementPolicyEOTAndCTD() throws AccountApiException, EntitlementApiException, SubscriptionApiException, SubscriptionBaseApiException {
         final LocalDate initialDate = new LocalDate(2013, 8, 7);
         clock.setDay(initialDate);
 
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
index 97422e1..77f5457 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
@@ -21,6 +21,7 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -107,7 +108,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
 
     @Test(groups = "slow")
-    public void testUncancelEffectiveCancelledEntitlement() throws AccountApiException, EntitlementApiException {
+    public void testUncancelEffectiveCancelledEntitlement() throws AccountApiException, EntitlementApiException, SubscriptionBaseApiException {
         final LocalDate initialDate = new LocalDate(2013, 8, 7);
         clock.setDay(initialDate);
 
@@ -396,7 +397,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
     }
 
     @Test(groups = "slow")
-    public void testTransferBundle() throws AccountApiException, EntitlementApiException {
+    public void testTransferBundle() throws AccountApiException, EntitlementApiException, SubscriptionBaseApiException {
         final LocalDate initialDate = new LocalDate(2013, 8, 7);
         clock.setDay(initialDate);
 
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java b/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
index 75db4db..760de7d 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
@@ -140,7 +140,7 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
     private Catalog initCatalog(final CatalogService catalogService) throws Exception {
 
         ((DefaultCatalogService) catalogService).loadCatalog();
-        final Catalog catalog = catalogService.getFullCatalog();
+        final Catalog catalog = catalogService.getFullCatalog(internalCallContext);
         assertNotNull(catalog);
         return catalog;
     }
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/glue/TestEntitlementModule.java b/entitlement/src/test/java/org/killbill/billing/entitlement/glue/TestEntitlementModule.java
index d607de1..78b500e 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/glue/TestEntitlementModule.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/glue/TestEntitlementModule.java
@@ -18,6 +18,7 @@
 
 package org.killbill.billing.entitlement.glue;
 
+import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.util.glue.CacheModule;
 import org.killbill.billing.util.glue.CallContextModule;
@@ -36,5 +37,6 @@ public class TestEntitlementModule extends DefaultEntitlementModule {
         super.configure();
         install(new CacheModule(configSource));
         install(new CallContextModule(configSource));
+        install(new MockTenantModule(configSource));
     }
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index 6e2c67a..8debd89 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -41,6 +41,7 @@ import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.Usage;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
@@ -311,6 +312,12 @@ public class InvoiceDispatcher {
         } catch (final AccountApiException e) {
             log.error("Failed handling SubscriptionBase change.", e);
             return null;
+        } catch (CatalogApiException e) {
+            log.error("Failed handling SubscriptionBase change.", e);
+            return null;
+        } catch (SubscriptionBaseApiException e) {
+            log.error("Failed handling SubscriptionBase change.", e);
+            return null;
         }
     }
 
@@ -409,7 +416,7 @@ public class InvoiceDispatcher {
     private void setChargedThroughDates(final DateAndTimeZoneContext dateAndTimeZoneContext,
                                         final Collection<InvoiceItem> fixedPriceItems,
                                         final Collection<InvoiceItem> recurringItems,
-                                        final InternalCallContext context) {
+                                        final InternalCallContext context) throws SubscriptionBaseApiException {
         final Map<UUID, DateTime> chargeThroughDates = new HashMap<UUID, DateTime>();
         addInvoiceItemsToChargeThroughDates(dateAndTimeZoneContext, chargeThroughDates, fixedPriceItems);
         addInvoiceItemsToChargeThroughDates(dateAndTimeZoneContext, chargeThroughDates, recurringItems);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
index 2467a92..a596d64 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
@@ -21,6 +21,7 @@ package org.killbill.billing.invoice.glue;
 import org.killbill.billing.catalog.glue.CatalogModule;
 import org.killbill.billing.invoice.TestInvoiceHelper;
 import org.killbill.billing.junction.BillingInternalApi;
+import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.usage.glue.UsageModule;
@@ -54,6 +55,8 @@ public class TestInvoiceModule extends DefaultInvoiceModule {
         install(new CacheModule(configSource));
         install(new TemplateModule(configSource));
         install(new EmailModule(configSource));
+        install(new MockTenantModule(configSource));
+
 
         install(new TagStoreModule(configSource));
         install(new CustomFieldModule(configSource));
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
index c184a59..83c6bc6 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
@@ -34,6 +34,7 @@ import org.killbill.billing.catalog.MockPlan;
 import org.killbill.billing.catalog.MockPlanPhase;
 import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.Plan;
@@ -76,7 +77,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testDryRunInvoice() throws InvoiceApiException, AccountApiException {
+    public void testDryRunInvoice() throws InvoiceApiException, AccountApiException, CatalogApiException {
         final UUID accountId = account.getId();
 
         final BillingEventSet events = new MockBillingEventSet();

jaxrs/pom.xml 4(+4 -0)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index 321a16c..1ca264c 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -96,6 +96,10 @@
         </dependency>
         <dependency>
             <groupId>org.kill-bill.billing</groupId>
+            <artifactId>killbill-catalog</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.kill-bill.billing</groupId>
             <artifactId>killbill-internal-api</artifactId>
         </dependency>
         <dependency>
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
index aa2458a..a079b44 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
@@ -16,22 +16,30 @@
 
 package org.killbill.billing.jaxrs.resources;
 
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.DefaultValue;
+import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
 
 import org.killbill.billing.account.api.AccountUserApi;
+import org.killbill.billing.catalog.StandaloneCatalog;
+import org.killbill.billing.catalog.VersionedCatalog;
 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.Listing;
 import org.killbill.billing.catalog.api.StaticCatalog;
 import org.killbill.billing.jaxrs.json.CatalogJsonSimple;
@@ -39,10 +47,15 @@ import org.killbill.billing.jaxrs.json.PlanDetailJson;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 import org.killbill.billing.payment.api.PaymentApi;
+import org.killbill.billing.tenant.api.TenantKV.TenantKey;
+import org.killbill.billing.tenant.api.TenantUserApi;
 import org.killbill.billing.util.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldUserApi;
 import org.killbill.billing.util.api.TagUserApi;
+import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.clock.Clock;
+import org.killbill.xmlloader.XMLLoader;
 import org.killbill.xmlloader.XMLWriter;
 
 import com.codahale.metrics.annotation.Timed;
@@ -60,20 +73,26 @@ import static javax.ws.rs.core.MediaType.APPLICATION_XML;
 @Api(value = JaxrsResource.CATALOG_PATH, description = "Catalog information")
 public class CatalogResource extends JaxRsResourceBase {
 
-    private final CatalogService catalogService;
+    private final CatalogUserApi catalogUserApi;
+    private final TenantUserApi tenantApi;
+
+    // Catalog API don't quite support multiple catalogs per tenant
+    private static final String catalogName = "unused";
 
     @Inject
-    public CatalogResource(final CatalogService catalogService,
-                           final JaxrsUriBuilder uriBuilder,
+    public CatalogResource(final JaxrsUriBuilder uriBuilder,
                            final TagUserApi tagUserApi,
                            final CustomFieldUserApi customFieldUserApi,
                            final AuditUserApi auditUserApi,
                            final AccountUserApi accountUserApi,
                            final PaymentApi paymentApi,
+                           final TenantUserApi tenantApi,
+                           final CatalogUserApi catalogUserApi,
                            final Clock clock,
                            final Context context) {
         super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, clock, context);
-        this.catalogService = catalogService;
+        this.catalogUserApi = catalogUserApi;
+        this.tenantApi = tenantApi;
     }
 
     @Timed
@@ -82,7 +101,29 @@ public class CatalogResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve the full catalog as XML", response = String.class, hidden = true)
     @ApiResponses(value = {})
     public Response getCatalogXml(@javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
-        return Response.status(Status.OK).entity(XMLWriter.writeXML(catalogService.getCurrentCatalog(), StaticCatalog.class)).build();
+        final TenantContext tenantContext = context.createContext(request);
+        return Response.status(Status.OK).entity(XMLWriter.writeXML((VersionedCatalog) catalogUserApi.getCatalog(catalogName, tenantContext), VersionedCatalog.class)).build();
+    }
+
+    @Timed
+    @POST
+    @Produces(APPLICATION_XML)
+    @Consumes(APPLICATION_XML)
+    @ApiOperation(value = "Upload the full catalog as XML")
+    @ApiResponses(value = {})
+    public Response uploadCatalogXml(final String catalogXML,
+                                     @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                     @HeaderParam(HDR_REASON) final String reason,
+                                     @HeaderParam(HDR_COMMENT) final String comment,
+                                     @javax.ws.rs.core.Context final HttpServletRequest request,
+                                     @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+        // Validation purpose:  Will throw if bad XML or catalog validation fails
+        final InputStream stream = new ByteArrayInputStream(catalogXML.getBytes());
+        XMLLoader.getObjectFromStream(new URI(JaxrsResource.CATALOG_PATH), stream, StandaloneCatalog.class);
+
+        final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+        tenantApi.addTenantKeyValue(TenantKey.CATALOG.toString(), catalogXML, callContext);
+        return uriBuilder.buildResponse(uriInfo, CatalogResource.class, null, null);
     }
 
     @Timed
@@ -91,8 +132,8 @@ public class CatalogResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve the full catalog as JSON", response = StaticCatalog.class)
     @ApiResponses(value = {})
     public Response getCatalogJson(@javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
-        final StaticCatalog catalog = catalogService.getCurrentCatalog();
-
+        final TenantContext tenantContext = context.createContext(request);
+        final StaticCatalog catalog = catalogUserApi.getCurrentCatalog(catalogName, tenantContext);
         return Response.status(Status.OK).entity(catalog).build();
     }
 
@@ -119,7 +160,8 @@ public class CatalogResource extends JaxRsResourceBase {
     public Response getAvailableAddons(@QueryParam("baseProductName") final String baseProductName,
                                        @Nullable @QueryParam("priceListName") final String priceListName,
                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws CatalogApiException {
-        final StaticCatalog catalog = catalogService.getCurrentCatalog();
+        final TenantContext tenantContext = context.createContext(request);
+        final StaticCatalog catalog = catalogUserApi.getCurrentCatalog(catalogName, tenantContext);
         final List<Listing> listings = catalog.getAvailableAddOnListings(baseProductName, priceListName);
         final List<PlanDetailJson> details = new ArrayList<PlanDetailJson>();
         for (final Listing listing : listings) {
@@ -135,7 +177,8 @@ public class CatalogResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve available base plans", response = PlanDetailJson.class, responseContainer = "List")
     @ApiResponses(value = {})
     public Response getAvailableBasePlans(@javax.ws.rs.core.Context final HttpServletRequest request) throws CatalogApiException {
-        final StaticCatalog catalog = catalogService.getCurrentCatalog();
+        final TenantContext tenantContext = context.createContext(request);
+        final StaticCatalog catalog = catalogUserApi.getCurrentCatalog(catalogName, tenantContext);
         final List<Listing> listings = catalog.getAvailableBasePlanListings();
         final List<PlanDetailJson> details = new ArrayList<PlanDetailJson>();
         for (final Listing listing : listings) {
@@ -151,8 +194,8 @@ public class CatalogResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a summarized version of the catalog as JSON", response = CatalogJsonSimple.class)
     @ApiResponses(value = {})
     public Response getSimpleCatalog(@javax.ws.rs.core.Context final HttpServletRequest request) throws CatalogApiException {
-        final StaticCatalog catalog = catalogService.getCurrentCatalog();
-
+        final TenantContext tenantContext = context.createContext(request);
+        final StaticCatalog catalog = catalogUserApi.getCurrentCatalog(catalogName, tenantContext);
         final CatalogJsonSimple json = new CatalogJsonSimple(catalog);
         return Response.status(Status.OK).entity(json).build();
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
index e4f8827..ee1d165 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
@@ -19,6 +19,7 @@ package org.killbill.billing.jaxrs.util;
 import java.net.URI;
 import java.util.Map;
 
+import javax.annotation.Nullable;
 import javax.ws.rs.Path;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
@@ -69,9 +70,11 @@ public class JaxrsUriBuilder {
         return ri.entity(obj).build();
     }
 
-    private UriBuilder getUriBuilder(final Class<? extends JaxrsResource> theClassMaybeEnhanced, final String getMethodName) {
+    private UriBuilder getUriBuilder(final Class<? extends JaxrsResource> theClassMaybeEnhanced, @Nullable final String getMethodName) {
         final Class theClass = getNonEnhancedClass(theClassMaybeEnhanced);
-        return UriBuilder.fromResource(theClass).path(theClass, getMethodName);
+        return getMethodName != null ? UriBuilder.fromResource(theClass).path(theClass, getMethodName) :
+               UriBuilder.fromResource(theClass);
+
     }
 
     private Class getNonEnhancedClass(final Class<? extends JaxrsResource> theClassMaybeEnhanced) {
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index 20d06c9..24923f7 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -64,7 +64,7 @@ public class BillCycleDayCalculator {
     protected int calculateBcd(final UUID bundleId, final SubscriptionBase subscription, final EffectiveSubscriptionInternalEvent transition, final Account account, final InternalCallContext context)
             throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
 
-        final Catalog catalog = catalogService.getFullCatalog();
+        final Catalog catalog = catalogService.getFullCatalog(context);
 
         final Plan prevPlan = (transition.getPreviousPlan() != null) ? catalog.findPlan(transition.getPreviousPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
         final Plan nextPlan = (transition.getNextPlan() != null) ? catalog.findPlan(transition.getNextPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index 07d0b3b..4b028a3 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -30,6 +30,7 @@ import org.killbill.billing.account.api.MutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
+import org.killbill.billing.catalog.api.StaticCatalog;
 import org.killbill.billing.entitlement.EntitlementTransitionType;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
@@ -81,10 +82,11 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
     }
 
     @Override
-    public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(final UUID accountId, final DryRunArguments dryRunArguments, final InternalCallContext context) {
+    public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(final UUID accountId, final DryRunArguments dryRunArguments, final InternalCallContext context) throws CatalogApiException {
         final List<SubscriptionBaseBundle> bundles = subscriptionApi.getBundlesForAccount(accountId, context);
         final DefaultBillingEventSet result = new DefaultBillingEventSet();
-        result.setRecurrringBillingMode(catalogService.getCurrentCatalog().getRecurringBillingMode());
+        final StaticCatalog currentCatalog = catalogService.getCurrentCatalog(context);
+        result.setRecurrringBillingMode(currentCatalog.getRecurringBillingMode());
 
         try {
             final Account account = accountApi.getAccountById(accountId, context);
@@ -183,7 +185,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
                         updatedAccountBCD = true;
                     }
 
-                    final BillingEvent event = new DefaultBillingEvent(account, transition, subscription, bcdLocal, account.getCurrency(), catalogService.getFullCatalog());
+                    final BillingEvent event = new DefaultBillingEvent(account, transition, subscription, bcdLocal, account.getCurrency(), catalogService.getFullCatalog(context));
                     result.add(event);
                 } catch (CatalogApiException e) {
                     log.error("Failing to identify catalog components while creating BillingEvent from transition: " +
diff --git a/junction/src/test/java/org/killbill/billing/junction/glue/TestJunctionModule.java b/junction/src/test/java/org/killbill/billing/junction/glue/TestJunctionModule.java
index 308c776..93e461b 100644
--- a/junction/src/test/java/org/killbill/billing/junction/glue/TestJunctionModule.java
+++ b/junction/src/test/java/org/killbill/billing/junction/glue/TestJunctionModule.java
@@ -25,6 +25,7 @@ import org.killbill.billing.entitlement.dao.BlockingStateDao;
 import org.killbill.billing.entitlement.dao.MockBlockingStateDao;
 import org.killbill.billing.junction.BlockingInternalApi;
 import org.killbill.billing.mock.glue.MockEntitlementModule;
+import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.util.glue.CacheModule;
 import org.killbill.billing.util.glue.CallContextModule;
@@ -41,6 +42,7 @@ public class TestJunctionModule extends DefaultJunctionModule {
 
         install(new CacheModule(configSource));
         install(new CallContextModule(configSource));
+        install(new MockTenantModule(configSource));
     }
 
     public class MockEntitlementModuleForJunction extends MockEntitlementModule {
diff --git a/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java b/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
index 15389f2..4327199 100644
--- a/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
+++ b/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
@@ -118,7 +118,7 @@ public abstract class JunctionTestSuiteWithEmbeddedDB extends GuicyKillbillTestS
 
     private Catalog initCatalog(final CatalogService catalogService) throws Exception {
         ((DefaultCatalogService) catalogService).loadCatalog();
-        final Catalog catalog = catalogService.getFullCatalog();
+        final Catalog catalog = catalogService.getFullCatalog(internalCallContext);
         assertNotNull(catalog);
         return catalog;
     }
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
index 1180e15..4acd3e2 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
@@ -99,9 +99,9 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
         Mockito.when(subscriptionInternalApi.getBillingTransitions(Mockito.<SubscriptionBase>any(),  Mockito.<InternalTenantContext>any())).thenReturn(effectiveSubscriptionTransitions);
         Mockito.when(subscriptionInternalApi.getAllTransitions(Mockito.<SubscriptionBase>any(), Mockito.<InternalTenantContext>any())).thenReturn(effectiveSubscriptionTransitions);
 
-        catalog = ((MockCatalog) catalogService.getCurrentCatalog());
+        catalog = ((MockCatalog) catalogService.getCurrentCatalog(internalCallContext));
         // TODO The MockCatalog module returns two different things for full vs current catalog
-        Mockito.when(catalogService.getFullCatalog()).thenReturn(catalog);
+        Mockito.when(catalogService.getFullCatalog(internalCallContext)).thenReturn(catalog);
         // Set a default alignment
         catalog.setBillingAlignment(BillingAlignment.ACCOUNT);
 
@@ -111,7 +111,7 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsEmpty() throws AccountApiException {
+    public void testBillingEventsEmpty() throws AccountApiException, CatalogApiException {
         final SortedSet<BillingEvent> events = billingInternalApi.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L, 0L), null, internalCallContext);
         Assert.assertEquals(events.size(), 0);
     }
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java b/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
index 131e9f4..bac5878 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
@@ -22,6 +22,7 @@ import org.killbill.billing.mock.glue.MockAccountModule;
 import org.killbill.billing.mock.glue.MockEntitlementModule;
 import org.killbill.billing.mock.glue.MockInvoiceModule;
 import org.killbill.billing.mock.glue.MockTagModule;
+import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.overdue.TestOverdueHelper;
 import org.killbill.billing.overdue.applicator.OverdueBusListenerTester;
 import org.killbill.billing.platform.api.KillbillConfigSource;
@@ -52,6 +53,8 @@ public class TestOverdueModule extends DefaultOverdueModule {
         install(new MockInvoiceModule(configSource));
         install(new MockTagModule(configSource));
         install(new TemplateModule(configSource));
+        install(new MockTenantModule(configSource));
+
 
         // We can't use the dumb mocks in MockJunctionModule here
         install(new ApplicatorMockJunctionModule(configSource));
diff --git a/payment/src/test/java/org/killbill/billing/payment/glue/TestPaymentModule.java b/payment/src/test/java/org/killbill/billing/payment/glue/TestPaymentModule.java
index 3ea946b..ca64630 100644
--- a/payment/src/test/java/org/killbill/billing/payment/glue/TestPaymentModule.java
+++ b/payment/src/test/java/org/killbill/billing/payment/glue/TestPaymentModule.java
@@ -25,6 +25,7 @@ import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.mock.glue.MockAccountModule;
 import org.killbill.billing.mock.glue.MockInvoiceModule;
 import org.killbill.billing.mock.glue.MockSubscriptionModule;
+import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.payment.TestPaymentHelper;
 import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
 import org.killbill.billing.payment.provider.MockPaymentProviderPluginModule;
@@ -70,6 +71,7 @@ public class TestPaymentModule extends PaymentModule {
         install(new MockAccountModule(configSource));
         install(new MockSubscriptionModule(configSource));
         install(new MemoryGlobalLockerModule(configSource));
+        install(new MockTenantModule(configSource));
         install(new CacheModule(configSource));
         installExternalApis();
         bind(TestPaymentHelper.class).asEagerSingleton();
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
index f9ef05a..32284cd 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
@@ -54,7 +54,7 @@ import org.killbill.billing.server.config.KillbillServerConfig;
 import org.killbill.billing.server.filters.ResponseCorsFilter;
 import org.killbill.billing.server.notifications.PushNotificationListener;
 import org.killbill.billing.subscription.glue.DefaultSubscriptionModule;
-import org.killbill.billing.tenant.glue.TenantModule;
+import org.killbill.billing.tenant.glue.DefaultTenantModule;
 import org.killbill.billing.usage.glue.UsageModule;
 import org.killbill.billing.util.dao.AuditLogModelDaoMapper;
 import org.killbill.billing.util.dao.RecordIdIdMappingsMapper;
@@ -147,7 +147,7 @@ public class KillbillServerModule extends KillbillPlatformModule {
         install(new SecurityModule(configSource));
         install(new TagStoreModule(configSource));
         install(new TemplateModule(configSource));
-        install(new TenantModule(configSource));
+        install(new DefaultTenantModule(configSource));
         install(new UsageModule(configSource));
     }
 
diff --git a/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java b/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
index 2f42574..83ba0be 100644
--- a/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
+++ b/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
@@ -43,7 +43,7 @@ import org.killbill.billing.payment.glue.PaymentModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.server.config.KillbillServerConfig;
 import org.killbill.billing.subscription.glue.DefaultSubscriptionModule;
-import org.killbill.billing.tenant.glue.TenantModule;
+import org.killbill.billing.tenant.glue.DefaultTenantModule;
 import org.killbill.billing.usage.glue.UsageModule;
 import org.killbill.billing.util.email.EmailModule;
 import org.killbill.billing.util.email.templates.TemplateModule;
@@ -85,7 +85,7 @@ public class KillpayServerModule extends KillbillServerModule {
         install(new RecordIdModule(configSource));
         install(new SecurityModule(configSource));
         install(new TagStoreModule(configSource));
-        install(new TenantModule(configSource));
+        install(new DefaultTenantModule(configSource));
 
         // TODO Required by payment for InvoiceInternalApi and InvoicePaymentApi
         install(new DefaultInvoiceModule(configSource));
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/alignment/MigrationPlanAligner.java b/subscription/src/main/java/org/killbill/billing/subscription/alignment/MigrationPlanAligner.java
index ed23c49..1996237 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/alignment/MigrationPlanAligner.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/alignment/MigrationPlanAligner.java
@@ -18,6 +18,7 @@ package org.killbill.billing.subscription.alignment;
 
 import org.joda.time.DateTime;
 
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
 import org.killbill.billing.catalog.api.Duration;
@@ -42,15 +43,15 @@ public class MigrationPlanAligner extends BaseAligner {
     }
 
 
-    public TimedMigration[] getEventsMigration(final SubscriptionMigrationCase[] input, final DateTime now)
+    public TimedMigration[] getEventsMigration(final SubscriptionMigrationCase[] input, final DateTime now, final InternalTenantContext context)
             throws SubscriptionBaseMigrationApiException {
 
         try {
             TimedMigration[] events;
-            final Plan plan0 = catalogService.getFullCatalog().findPlan(input[0].getPlanPhaseSpecifier().getProductName(),
+            final Plan plan0 = catalogService.getFullCatalog(context).findPlan(input[0].getPlanPhaseSpecifier().getProductName(),
                                                                         input[0].getPlanPhaseSpecifier().getBillingPeriod(), input[0].getPlanPhaseSpecifier().getPriceListName(), now);
 
-            final Plan plan1 = (input.length > 1) ? catalogService.getFullCatalog().findPlan(input[1].getPlanPhaseSpecifier().getProductName(),
+            final Plan plan1 = (input.length > 1) ? catalogService.getFullCatalog(context).findPlan(input[1].getPlanPhaseSpecifier().getProductName(),
                                                                                              input[1].getPlanPhaseSpecifier().getBillingPeriod(), input[1].getPlanPhaseSpecifier().getPriceListName(), now) :
                                null;
 
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
index 4c194cc..345388f 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
@@ -26,6 +26,7 @@ import javax.inject.Inject;
 import org.joda.time.DateTime;
 
 import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
@@ -81,13 +82,15 @@ public class PlanAligner extends BaseAligner {
                                                             @Nullable final PhaseType initialPhase,
                                                             final String priceList,
                                                             final DateTime requestedDate,
-                                                            final DateTime effectiveDate) throws CatalogApiException, SubscriptionBaseApiException {
+                                                            final DateTime effectiveDate,
+                                                            final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
         final List<TimedPhase> timedPhases = getTimedPhaseOnCreate(alignStartDate,
                                                                    bundleStartDate,
                                                                    plan,
                                                                    initialPhase,
                                                                    priceList,
-                                                                   requestedDate);
+                                                                   requestedDate,
+                                                                   context);
         final TimedPhase[] result = new TimedPhase[2];
         result[0] = getTimedPhase(timedPhases, effectiveDate, WhichPhase.CURRENT);
         result[1] = getTimedPhase(timedPhases, effectiveDate, WhichPhase.NEXT);
@@ -111,8 +114,9 @@ public class PlanAligner extends BaseAligner {
                                                    final Plan plan,
                                                    final String priceList,
                                                    final DateTime requestedDate,
-                                                   final DateTime effectiveDate) throws CatalogApiException, SubscriptionBaseApiException {
-        return getTimedPhaseOnChange(subscription, plan, priceList, requestedDate, effectiveDate, WhichPhase.CURRENT);
+                                                   final DateTime effectiveDate,
+                                                   final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
+        return getTimedPhaseOnChange(subscription, plan, priceList, requestedDate, effectiveDate, WhichPhase.CURRENT, context);
     }
 
     /**
@@ -132,8 +136,9 @@ public class PlanAligner extends BaseAligner {
                                                 final Plan plan,
                                                 final String priceList,
                                                 final DateTime requestedDate,
-                                                final DateTime effectiveDate) throws CatalogApiException, SubscriptionBaseApiException {
-        return getTimedPhaseOnChange(subscription, plan, priceList, requestedDate, effectiveDate, WhichPhase.NEXT);
+                                                final DateTime effectiveDate,
+                                                final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
+        return getTimedPhaseOnChange(subscription, plan, priceList, requestedDate, effectiveDate, WhichPhase.NEXT, context);
     }
 
     /**
@@ -144,7 +149,7 @@ public class PlanAligner extends BaseAligner {
      * @param effectiveDate the date at which we look to compute that event. effective needs to be after last Plan change or initial Plan
      * @return the next phase
      */
-    public TimedPhase getNextTimedPhase(final DefaultSubscriptionBase subscription, final DateTime requestedDate, final DateTime effectiveDate) {
+    public TimedPhase getNextTimedPhase(final DefaultSubscriptionBase subscription, final DateTime requestedDate, final DateTime effectiveDate, final InternalTenantContext context) {
         try {
             final SubscriptionBaseTransitionData lastPlanTransition = subscription.getInitialTransitionForCurrentPlan();
             if (effectiveDate.isBefore(lastPlanTransition.getEffectiveTransitionTime())) {
@@ -163,7 +168,8 @@ public class PlanAligner extends BaseAligner {
                                                                                lastPlanTransition.getNextPlan(),
                                                                                lastPlanTransition.getNextPhase().getPhaseType(),
                                                                                lastPlanTransition.getNextPriceList().getName(),
-                                                                               requestedDate);
+                                                                               requestedDate,
+                                                                               context);
                     return getTimedPhase(timedPhases, effectiveDate, WhichPhase.NEXT);
                 // If we went through Plan changes, borrow the logic for changePlanWithRequestedDate alignment
                 case CHANGE:
@@ -176,7 +182,8 @@ public class PlanAligner extends BaseAligner {
                                                  lastPlanTransition.getNextPriceList().getName(),
                                                  requestedDate,
                                                  effectiveDate,
-                                                 WhichPhase.NEXT);
+                                                 WhichPhase.NEXT,
+                                                 context);
                 default:
                     throw new SubscriptionBaseError(String.format("Unexpected initial transition %s for current plan %s on subscription %s",
                                                              lastPlanTransition.getTransitionType(), subscription.getCurrentPlan(), subscription.getId()));
@@ -191,9 +198,10 @@ public class PlanAligner extends BaseAligner {
                                                    final Plan plan,
                                                    @Nullable final PhaseType initialPhase,
                                                    final String priceList,
-                                                   final DateTime requestedDate)
+                                                   final DateTime requestedDate,
+                                                   final InternalTenantContext context)
             throws CatalogApiException, SubscriptionBaseApiException {
-        final Catalog catalog = catalogService.getFullCatalog();
+        final Catalog catalog = catalogService.getFullCatalog(context);
 
         final PlanSpecifier planSpecifier = new PlanSpecifier(plan.getProduct().getName(),
                                                               plan.getProduct().getCategory(),
@@ -221,7 +229,8 @@ public class PlanAligner extends BaseAligner {
                                              final String nextPriceList,
                                              final DateTime requestedDate,
                                              final DateTime effectiveDate,
-                                             final WhichPhase which) throws CatalogApiException, SubscriptionBaseApiException {
+                                             final WhichPhase which,
+                                             final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
         return getTimedPhaseOnChange(subscription.getAlignStartDate(),
                                      subscription.getBundleStartDate(),
                                      subscription.getCurrentPhase(),
@@ -231,7 +240,8 @@ public class PlanAligner extends BaseAligner {
                                      nextPriceList,
                                      requestedDate,
                                      effectiveDate,
-                                     which);
+                                     which,
+                                     context);
     }
 
     private TimedPhase getTimedPhaseOnChange(final DateTime subscriptionStartDate,
@@ -243,8 +253,9 @@ public class PlanAligner extends BaseAligner {
                                              final String priceList,
                                              final DateTime requestedDate,
                                              final DateTime effectiveDate,
-                                             final WhichPhase which) throws CatalogApiException, SubscriptionBaseApiException {
-        final Catalog catalog = catalogService.getFullCatalog();
+                                             final WhichPhase which,
+                                             final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
+        final Catalog catalog = catalogService.getFullCatalog(context);
         final ProductCategory currentCategory = currentPlan.getProduct().getCategory();
         final PlanPhaseSpecifier fromPlanPhaseSpecifier = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
                                                                                  currentCategory,
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java
index af51ce0..218b7d7 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java
@@ -25,6 +25,8 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.clock.Clock;
@@ -116,10 +118,10 @@ public class DefaultSubscriptionBaseMigrationApi extends SubscriptionApiBase imp
             for (final SubscriptionMigration curSub : sortedSubscriptions) {
                 SubscriptionMigrationData data = null;
                 if (bundleStartDate == null) {
-                    data = createInitialSubscription(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now, curSub.getChargedThroughDate(), context);
+                    data = createInitialSubscription(accountId, bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now, curSub.getChargedThroughDate(), context);
                     bundleStartDate = data.getInitialEvents().get(0).getEffectiveDate();
                 } else {
-                    data = createSubscriptionMigrationDataWithBundleDate(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now,
+                    data = createSubscriptionMigrationDataWithBundleDate(accountId, bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now,
                                                                          bundleStartDate, curSub.getChargedThroughDate(), context);
                 }
                 if (data != null) {
@@ -133,41 +135,54 @@ public class DefaultSubscriptionBaseMigrationApi extends SubscriptionApiBase imp
         return new AccountMigrationData(accountBundleData);
     }
 
-    private SubscriptionMigrationData createInitialSubscription(final UUID bundleId, final ProductCategory productCategory,
+    private SubscriptionMigrationData createInitialSubscription(final UUID accountId, final UUID bundleId, final ProductCategory productCategory,
                                                                 final SubscriptionMigrationCase[] input, final DateTime now, final DateTime ctd, final CallContext context)
             throws SubscriptionBaseMigrationApiException {
-        final TimedMigration[] events = migrationAligner.getEventsMigration(input, now);
+
+        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(accountId, context);
+        final TimedMigration[] events = migrationAligner.getEventsMigration(input, now, internalCallContext);
         final DateTime migrationStartDate = events[0].getEventTime();
         final List<SubscriptionBaseEvent> emptyEvents = Collections.emptyList();
-        final DefaultSubscriptionBase defaultSubscriptionBase = createSubscriptionForApiUse(new SubscriptionBuilder()
-                                                                                      .setId(UUID.randomUUID())
-                                                                                      .setBundleId(bundleId)
-                                                                                      .setCategory(productCategory)
-                                                                                      .setBundleStartDate(migrationStartDate)
-                                                                                      .setAlignStartDate(migrationStartDate),
-                                                                              emptyEvents);
-        return new SubscriptionMigrationData(defaultSubscriptionBase, toEvents(defaultSubscriptionBase, now, ctd, events, context), ctd);
+
+        final DefaultSubscriptionBase defaultSubscriptionBase;
+        try {
+            defaultSubscriptionBase = createSubscriptionForApiUse(new SubscriptionBuilder()
+                                                                          .setId(UUID.randomUUID())
+                                                                          .setBundleId(bundleId)
+                                                                          .setCategory(productCategory)
+                                                                          .setBundleStartDate(migrationStartDate)
+                                                                          .setAlignStartDate(migrationStartDate),
+                                                                  emptyEvents, internalCallContext);
+            return new SubscriptionMigrationData(defaultSubscriptionBase, toEvents(defaultSubscriptionBase, now, ctd, events, context), ctd);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseMigrationApiException(e);
+        }
     }
 
-    private SubscriptionMigrationData createSubscriptionMigrationDataWithBundleDate(final UUID bundleId, final ProductCategory productCategory,
+    private SubscriptionMigrationData createSubscriptionMigrationDataWithBundleDate(final UUID accountId, final UUID bundleId, final ProductCategory productCategory,
                                                                                     final SubscriptionMigrationCase[] input, final DateTime now, final DateTime bundleStartDate, final DateTime ctd, final CallContext context)
             throws SubscriptionBaseMigrationApiException {
-        final TimedMigration[] events = migrationAligner.getEventsMigration(input, now);
+        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(accountId, context);
+        final TimedMigration[] events = migrationAligner.getEventsMigration(input, now, internalCallContext);
         final DateTime migrationStartDate = events[0].getEventTime();
         final List<SubscriptionBaseEvent> emptyEvents = Collections.emptyList();
-        final DefaultSubscriptionBase defaultSubscriptionBase = createSubscriptionForApiUse(new SubscriptionBuilder()
-                                                                                      .setId(UUID.randomUUID())
-                                                                                      .setBundleId(bundleId)
-                                                                                      .setCategory(productCategory)
-                                                                                      .setBundleStartDate(bundleStartDate)
-                                                                                      .setAlignStartDate(migrationStartDate),
-                                                                              emptyEvents);
-        return new SubscriptionMigrationData(defaultSubscriptionBase, toEvents(defaultSubscriptionBase, now, ctd, events, context), ctd);
+        final DefaultSubscriptionBase defaultSubscriptionBase;
+        try {
+            defaultSubscriptionBase = createSubscriptionForApiUse(new SubscriptionBuilder()
+                                                                                                        .setId(UUID.randomUUID())
+                                                                                                        .setBundleId(bundleId)
+                                                                                                        .setCategory(productCategory)
+                                                                                                        .setBundleStartDate(bundleStartDate)
+                                                                                                        .setAlignStartDate(migrationStartDate),
+                                                                                                emptyEvents, internalCallContext);
+            return new SubscriptionMigrationData(defaultSubscriptionBase, toEvents(defaultSubscriptionBase, now, ctd, events, context), ctd);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseMigrationApiException(e);
+        }
     }
 
     private List<SubscriptionBaseEvent> toEvents(final DefaultSubscriptionBase defaultSubscriptionBase, final DateTime now, final DateTime ctd, final TimedMigration[] migrationEvents, final CallContext context) {
 
-
         if (ctd == null) {
             throw new SubscriptionBaseError(String.format("Could not create migration billing event ctd = %s", ctd));
         }
@@ -183,7 +198,6 @@ public class DefaultSubscriptionBaseMigrationApi extends SubscriptionApiBase imp
 
         for (final TimedMigration cur : migrationEvents) {
 
-
             final ApiEventBuilder builder = new ApiEventBuilder()
                     .setSubscriptionId(defaultSubscriptionBase.getId())
                     .setEventPlan((cur.getPlan() != null) ? cur.getPlan().getName() : null)
@@ -195,14 +209,12 @@ public class DefaultSubscriptionBaseMigrationApi extends SubscriptionApiBase imp
                     .setRequestedDate(now)
                     .setFromDisk(true);
 
-
             if (cur.getEventType() == EventType.PHASE) {
                 nextEventDate = nextEventDate != null && nextEventDate.compareTo(cur.getEventTime()) < 0 ? nextEventDate : cur.getEventTime();
                 final PhaseEvent nextPhaseEvent = PhaseEventData.createNextPhaseEvent(defaultSubscriptionBase.getId(), defaultSubscriptionBase.getActiveVersion(),
                                                                                       cur.getPhase().getName(), now, cur.getEventTime());
                 events.add(nextPhaseEvent);
 
-
             } else if (cur.getEventType() == EventType.API_USER) {
 
                 switch (cur.getApiEventType()) {
@@ -271,7 +283,6 @@ public class DefaultSubscriptionBaseMigrationApi extends SubscriptionApiBase imp
                 return comp;
             }
         });
-
         return events;
     }
 }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionApiBase.java b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionApiBase.java
index 14a29fe..e576d0e 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionApiBase.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionApiBase.java
@@ -19,6 +19,8 @@ package org.killbill.billing.subscription.api;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
 import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
@@ -57,10 +59,10 @@ public class SubscriptionApiBase {
         return new DefaultSubscriptionBase((DefaultSubscriptionBase) internalSubscription, apiService, clock);
     }
 
-    protected DefaultSubscriptionBase createSubscriptionForApiUse(SubscriptionBuilder builder, List<SubscriptionBaseEvent> events) {
+    protected DefaultSubscriptionBase createSubscriptionForApiUse(SubscriptionBuilder builder, List<SubscriptionBaseEvent> events, final InternalTenantContext context) throws CatalogApiException {
         final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(builder, apiService, clock);
         if (events.size() > 0) {
-            subscription.rebuildTransitions(events, catalogService.getFullCatalog());
+            subscription.rebuildTransitions(events, catalogService.getFullCatalog(context));
         }
         return subscription;
     }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
index 7f67068..1697726 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
@@ -73,15 +73,15 @@ public interface SubscriptionBaseApiService {
                                          String priceList, BillingActionPolicy policy, CallContext context)
             throws SubscriptionBaseApiException;
 
-    public int cancelAddOnsIfRequired(final Product baseProduct, final UUID bundleId, final DateTime effectiveDate, final CallContext context);
+    public int cancelAddOnsIfRequired(final Product baseProduct, final UUID bundleId, final DateTime effectiveDate, final CallContext context) throws CatalogApiException;
 
     public PlanChangeResult getPlanChangeResult(final DefaultSubscriptionBase subscription, final String productName,
-                                                final BillingPeriod term, final String priceList, final DateTime effectiveDate) throws SubscriptionBaseApiException;
+                                                final BillingPeriod term, final String priceList, final DateTime effectiveDate, TenantContext context) throws SubscriptionBaseApiException;
 
         //
     // Lower level APIs for dryRun functionality
     //
-    public List<SubscriptionBaseEvent> getEventsOnCreation(UUID subscriptionId, DateTime alignStartDate, DateTime bundleStartDate, long activeVersion,
+    public List<SubscriptionBaseEvent> getEventsOnCreation(UUID bundleId, UUID subscriptionId, DateTime alignStartDate, DateTime bundleStartDate, long activeVersion,
                                                            Plan plan, PhaseType initialPhase,
                                                            String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate,
                                                            boolean reCreate, TenantContext context)
@@ -94,5 +94,5 @@ public interface SubscriptionBaseApiService {
 
     public List<SubscriptionBaseEvent> getEventsOnCancelPlan(final DefaultSubscriptionBase subscription,
                                                              final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
-                                                             final boolean addCancellationAddOnForEventsIfRequired, final TenantContext context);
+                                                             final boolean addCancellationAddOnForEventsIfRequired, final TenantContext context) throws CatalogApiException;
 }
\ No newline at end of file
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index 9ba3261..c6ca83b 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -82,7 +82,7 @@ import static org.killbill.billing.util.entity.dao.DefaultPaginationHelper.getEn
 
 public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implements SubscriptionBaseInternalApi {
 
-    private final Logger log = LoggerFactory.getLogger(DefaultSubscriptionInternalApi.class);
+    private static final Logger log = LoggerFactory.getLogger(DefaultSubscriptionInternalApi.class);
 
     private final AddonUtils addonUtils;
     private final NonEntityDao nonEntityDao;
@@ -113,7 +113,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
             }
             final DateTime effectiveDate = requestedDate;
 
-            final Catalog catalog = catalogService.getFullCatalog();
+            final Catalog catalog = catalogService.getFullCatalog(context);
             final Plan plan = catalog.findPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, requestedDate);
             final PlanPhase phase = plan.getAllPhases()[0];
             if (phase == null) {
@@ -212,14 +212,20 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
     public static SubscriptionBaseBundle getActiveBundleForKeyNotException(final List<SubscriptionBaseBundle> existingBundles, final SubscriptionDao dao, final Clock clock, final InternalTenantContext context) {
         for (SubscriptionBaseBundle cur : existingBundles) {
-            final List<SubscriptionBase> subscriptions = dao.getSubscriptions(cur.getId(), ImmutableList.<SubscriptionBaseEvent>of(), context);
-            for (SubscriptionBase s : subscriptions) {
-                if (s.getCategory() == ProductCategory.ADD_ON) {
-                    continue;
-                }
-                if (s.getEndDate() == null || s.getEndDate().compareTo(clock.getUTCNow()) > 0) {
-                    return cur;
+            final List<SubscriptionBase> subscriptions;
+            try {
+                subscriptions = dao.getSubscriptions(cur.getId(), ImmutableList.<SubscriptionBaseEvent>of(), context);
+                for (SubscriptionBase s : subscriptions) {
+                    if (s.getCategory() == ProductCategory.ADD_ON) {
+                        continue;
+                    }
+                    if (s.getEndDate() == null || s.getEndDate().compareTo(clock.getUTCNow()) > 0) {
+                        return cur;
+                    }
                 }
+            } catch (CatalogApiException e) {
+                log.warn("Failed to get subscriptions, ", e);
+                return null;
             }
         }
         return null;
@@ -230,46 +236,63 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                                             @Nullable final DryRunArguments dryRunArguments,
                                                             InternalTenantContext context) throws SubscriptionBaseApiException {
 
-        final List<SubscriptionBaseEvent> outputDryRunEvents = new ArrayList<SubscriptionBaseEvent>();
-        final List<SubscriptionBase> outputSubscriptions = new ArrayList<SubscriptionBase>();
-
-        populateDryRunEvents(bundleId, dryRunArguments, outputDryRunEvents, outputSubscriptions, context);
-        final List<SubscriptionBase> result = dao.getSubscriptions(bundleId, outputDryRunEvents, context);
-        if (result != null && !result.isEmpty()) {
-            outputSubscriptions.addAll(result);
+        try {
+            final List<SubscriptionBaseEvent> outputDryRunEvents = new ArrayList<SubscriptionBaseEvent>();
+            final List<SubscriptionBase> outputSubscriptions = new ArrayList<SubscriptionBase>();
+
+            populateDryRunEvents(bundleId, dryRunArguments, outputDryRunEvents, outputSubscriptions, context);
+            final List<SubscriptionBase> result;
+            result = dao.getSubscriptions(bundleId, outputDryRunEvents, context);
+            if (result != null && !result.isEmpty()) {
+                outputSubscriptions.addAll(result);
+            }
+            return createSubscriptionsForApiUse(outputSubscriptions);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
         }
-        return createSubscriptionsForApiUse(outputSubscriptions);
     }
 
     @Override
-    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final InternalTenantContext context) {
-        final Map<UUID, List<SubscriptionBase>> internalSubscriptions = dao.getSubscriptionsForAccount(context);
-        final Map<UUID, List<SubscriptionBase>> result = new HashMap<UUID, List<SubscriptionBase>>();
-        for (final UUID bundleId : internalSubscriptions.keySet()) {
-            result.put(bundleId, createSubscriptionsForApiUse(internalSubscriptions.get(bundleId)));
+    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final InternalTenantContext context) throws SubscriptionBaseApiException {
+        try {
+            final Map<UUID, List<SubscriptionBase>> internalSubscriptions = dao.getSubscriptionsForAccount(context);
+            final Map<UUID, List<SubscriptionBase>> result = new HashMap<UUID, List<SubscriptionBase>>();
+            for (final UUID bundleId : internalSubscriptions.keySet()) {
+                result.put(bundleId, createSubscriptionsForApiUse(internalSubscriptions.get(bundleId)));
+            }
+            return result;
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
         }
-        return result;
     }
 
     @Override
     public SubscriptionBase getBaseSubscription(UUID bundleId,
                                                 InternalTenantContext context) throws SubscriptionBaseApiException {
-        final SubscriptionBase result = dao.getBaseSubscription(bundleId, context);
-        if (result == null) {
-            throw new SubscriptionBaseApiException(ErrorCode.SUB_GET_NO_SUCH_BASE_SUBSCRIPTION, bundleId);
+        try {
+            final SubscriptionBase result = dao.getBaseSubscription(bundleId, context);
+            if (result == null) {
+                throw new SubscriptionBaseApiException(ErrorCode.SUB_GET_NO_SUCH_BASE_SUBSCRIPTION, bundleId);
+            }
+            return createSubscriptionForApiUse(result);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
         }
-        return createSubscriptionForApiUse(result);
     }
 
     @Override
 
     public SubscriptionBase getSubscriptionFromId(UUID id,
                                                   InternalTenantContext context) throws SubscriptionBaseApiException {
-        final SubscriptionBase result = dao.getSubscriptionFromId(id, context);
-        if (result == null) {
-            throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_SUBSCRIPTION_ID, id);
+        try {
+            final SubscriptionBase result = dao.getSubscriptionFromId(id, context);
+            if (result == null) {
+                throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_SUBSCRIPTION_ID, id);
+            }
+            return createSubscriptionForApiUse(result);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
         }
-        return createSubscriptionForApiUse(result);
     }
 
     @Override
@@ -288,12 +311,16 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
     @Override
     public void setChargedThroughDate(UUID subscriptionId,
-                                      DateTime chargedThruDate, InternalCallContext context) {
-        final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(subscriptionId, context);
-        final SubscriptionBuilder builder = new SubscriptionBuilder(subscription)
-                .setChargedThroughDate(chargedThruDate);
+                                      DateTime chargedThruDate, InternalCallContext context) throws SubscriptionBaseApiException {
+        try {
+            final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(subscriptionId, context);
+            final SubscriptionBuilder builder = new SubscriptionBuilder(subscription)
+                    .setChargedThroughDate(chargedThruDate);
 
-        dao.updateChargedThroughDate(new DefaultSubscriptionBase(builder), context);
+            dao.updateChargedThroughDate(new DefaultSubscriptionBase(builder), context);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
     }
 
     @Override
@@ -310,44 +337,49 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
     @Override
     public List<EntitlementAOStatusDryRun> getDryRunChangePlanStatus(final UUID subscriptionId, @Nullable final String baseProductName, final DateTime requestedDate, final InternalTenantContext context) throws SubscriptionBaseApiException {
-        final SubscriptionBase subscription = dao.getSubscriptionFromId(subscriptionId, context);
-        if (subscription == null) {
-            throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_SUBSCRIPTION_ID, subscriptionId);
-        }
-        if (subscription.getCategory() != ProductCategory.BASE) {
-            throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_DRY_RUN_NOT_BP);
-        }
+        try {
+            final SubscriptionBase subscription = dao.getSubscriptionFromId(subscriptionId, context);
+            if (subscription == null) {
+                throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_SUBSCRIPTION_ID, subscriptionId);
+            }
+            if (subscription.getCategory() != ProductCategory.BASE) {
+                throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_DRY_RUN_NOT_BP);
+            }
 
-        final List<EntitlementAOStatusDryRun> result = new LinkedList<EntitlementAOStatusDryRun>();
+            final List<EntitlementAOStatusDryRun> result = new LinkedList<EntitlementAOStatusDryRun>();
 
-        final List<SubscriptionBase> bundleSubscriptions = dao.getSubscriptions(subscription.getBundleId(), ImmutableList.<SubscriptionBaseEvent>of(), context);
-        for (final SubscriptionBase cur : bundleSubscriptions) {
-            if (cur.getId().equals(subscriptionId)) {
-                continue;
-            }
+            final List<SubscriptionBase> bundleSubscriptions = dao.getSubscriptions(subscription.getBundleId(), ImmutableList.<SubscriptionBaseEvent>of(), context);
+            for (final SubscriptionBase cur : bundleSubscriptions) {
+                if (cur.getId().equals(subscriptionId)) {
+                    continue;
+                }
 
-            // If ADDON is cancelled, skip
-            if (cur.getState() == EntitlementState.CANCELLED) {
-                continue;
-            }
+                // If ADDON is cancelled, skip
+                if (cur.getState() == EntitlementState.CANCELLED) {
+                    continue;
+                }
 
-            final DryRunChangeReason reason;
-            // If baseProductName is null, it's a cancellation dry-run. In this case, return all addons, so they are cancelled
-            if (baseProductName != null && addonUtils.isAddonIncludedFromProdName(baseProductName, requestedDate, cur.getCurrentPlan())) {
-                reason = DryRunChangeReason.AO_INCLUDED_IN_NEW_PLAN;
-            } else if (baseProductName != null && addonUtils.isAddonAvailableFromProdName(baseProductName, requestedDate, cur.getCurrentPlan())) {
-                reason = DryRunChangeReason.AO_AVAILABLE_IN_NEW_PLAN;
-            } else {
-                reason = DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN;
+                final DryRunChangeReason reason;
+                // If baseProductName is null, it's a cancellation dry-run. In this case, return all addons, so they are cancelled
+                if (baseProductName != null && addonUtils.isAddonIncludedFromProdName(baseProductName, requestedDate, cur.getCurrentPlan(), context)) {
+                    reason = DryRunChangeReason.AO_INCLUDED_IN_NEW_PLAN;
+                } else if (baseProductName != null && addonUtils.isAddonAvailableFromProdName(baseProductName, requestedDate, cur.getCurrentPlan(), context)) {
+                    reason = DryRunChangeReason.AO_AVAILABLE_IN_NEW_PLAN;
+                } else {
+                    reason = DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN;
+                }
+                final EntitlementAOStatusDryRun status = new DefaultSubscriptionStatusDryRun(cur.getId(),
+                                                                                             cur.getCurrentPlan().getProduct().getName(),
+                                                                                             cur.getCurrentPhase().getPhaseType(),
+                                                                                             cur.getCurrentPlan().getRecurringBillingPeriod(),
+                                                                                             cur.getCurrentPriceList().getName(), reason);
+                result.add(status);
             }
-            final EntitlementAOStatusDryRun status = new DefaultSubscriptionStatusDryRun(cur.getId(),
-                                                                                         cur.getCurrentPlan().getProduct().getName(),
-                                                                                         cur.getCurrentPhase().getPhaseType(),
-                                                                                         cur.getCurrentPlan().getRecurringBillingPeriod(),
-                                                                                         cur.getCurrentPriceList().getName(), reason);
-            result.add(status);
+            return result;
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
         }
-        return result;
+
     }
 
     @Override
@@ -369,7 +401,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         try {
             final PlanPhaseSpecifier inputSpec = dryRunArguments.getPlanPhaseSpecifier();
             final String realPriceList = (inputSpec != null && inputSpec.getPriceListName() != null) ? inputSpec.getPriceListName() : PriceListSet.DEFAULT_PRICELIST_NAME;
-            final Catalog catalog = catalogService.getFullCatalog();
+            final Catalog catalog = catalogService.getFullCatalog(context);
             final Plan plan = (inputSpec != null && inputSpec.getProductName() != null && inputSpec.getBillingPeriod() != null) ?
                               catalog.findPlan(inputSpec.getProductName(), inputSpec.getBillingPeriod(), realPriceList, utcNow) : null;
             final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
@@ -382,7 +414,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                         final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? dryRunArguments.getEffectiveDate() : utcNow;
                         final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, startEffectiveDate);
                         final UUID subscriptionId = UUID.randomUUID();
-                        dryRunEvents = apiService.getEventsOnCreation(subscriptionId, startEffectiveDate, bundleStartDate, 1L, plan, inputSpec.getPhaseType(), realPriceList,
+                        dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, 1L, plan, inputSpec.getPhaseType(), realPriceList,
                                                                       utcNow, startEffectiveDate, utcNow, false, context.toTenantContext(tenantId));
                         final SubscriptionBuilder builder = new SubscriptionBuilder()
                                 .setId(subscriptionId)
@@ -404,7 +436,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                 final PlanChangeResult planChangeResult = apiService.getPlanChangeResult(subscriptionForChange,
                                                                                                          dryRunArguments.getPlanPhaseSpecifier().getProductName(),
                                                                                                          dryRunArguments.getPlanPhaseSpecifier().getBillingPeriod(),
-                                                                                                         dryRunArguments.getPlanPhaseSpecifier().getPriceListName(), utcNow);
+                                                                                                         dryRunArguments.getPlanPhaseSpecifier().getPriceListName(), utcNow, context.toTenantContext(tenantId));
                                 policy = planChangeResult.getPolicy();
                             }
                             changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy);
@@ -421,11 +453,11 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                                 final Plan currentPlan = subscriptionForCancellation.getCurrentPlan();
                                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                                                                                            currentPlan.getProduct().getCategory(),
-                                                                                            subscriptionForCancellation.getCurrentPlan().getRecurringBillingPeriod(),
-                                                                                            subscriptionForCancellation.getCurrentPriceList().getName(),
-                                                                                            subscriptionForCancellation.getCurrentPhase().getPhaseType());
-                                policy = catalogService.getFullCatalog().planCancelPolicy(spec, utcNow);
+                                                                                       currentPlan.getProduct().getCategory(),
+                                                                                       subscriptionForCancellation.getCurrentPlan().getRecurringBillingPeriod(),
+                                                                                       subscriptionForCancellation.getCurrentPriceList().getName(),
+                                                                                       subscriptionForCancellation.getCurrentPhase().getPhaseType());
+                                policy = catalogService.getFullCatalog(context).planCancelPolicy(spec, utcNow);
                             }
                             cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy);
                         }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java
index 01b74ae..4171cc0 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java
@@ -31,6 +31,7 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 
 import org.killbill.billing.ErrorCode;
+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.ProductCategory;
@@ -116,14 +117,15 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
             if (bundle == null) {
                 throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_UNKNOWN_BUNDLE, descBundle);
             }
+            final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(bundle.getAccountId(), context);
             final List<SubscriptionDataRepair> subscriptions = convertToSubscriptionsDataRepair(dao.getSubscriptions(bundle.getId(),
                                                                                                                      ImmutableList.<SubscriptionBaseEvent>of(),
-                                                                                                                     internalCallContextFactory.createInternalTenantContext(context)));
+                                                                                                                     internalTenantContext));
             if (subscriptions.size() == 0) {
                 throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_NO_ACTIVE_SUBSCRIPTIONS, bundle.getId());
             }
             final String viewId = getViewId(((DefaultSubscriptionBaseBundle) bundle).getLastSysUpdateDate(), subscriptions);
-            final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, Collections.<SubscriptionBaseTimeline>emptyList());
+            final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, Collections.<SubscriptionBaseTimeline>emptyList(), internalTenantContext);
             return createGetBundleRepair(bundle.getId(), bundle.getExternalKey(), viewId, repairs);
         } catch (CatalogApiException e) {
             throw new SubscriptionBaseRepairException(e);
@@ -206,7 +208,7 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
                         validateFirstNewEvent(curInputRepair, curRepair.getNewEvents().get(0), lastRemainingBPEventTime, lastRemainingEventTime);
                     }
 
-                    final SubscriptionDataRepair curOutputRepair = createSubscriptionDataRepair(curInputRepair, newBundleStartDate, newSubscriptionStartDate, remaining);
+                    final SubscriptionDataRepair curOutputRepair = createSubscriptionDataRepair(curInputRepair, newBundleStartDate, newSubscriptionStartDate, remaining, tenantContext);
                     repairDao.initializeRepair(curInputRepair.getId(), remaining, tenantContext);
                     inRepair.add(curOutputRepair);
                     if (curOutputRepair.getCategory() == ProductCategory.ADD_ON) {
@@ -227,7 +229,8 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
                     // We need to add any existing addon that are not in the input repair list
                     for (final SubscriptionBase cur : subscriptions) {
                         if (cur.getCategory() == ProductCategory.ADD_ON && !inRepair.contains(cur)) {
-                            final SubscriptionDataRepair curOutputRepair = createSubscriptionDataRepair((SubscriptionDataRepair) cur, newBundleStartDate, null, ((SubscriptionDataRepair) cur).getEvents());
+                            final SubscriptionDataRepair curOutputRepair = createSubscriptionDataRepair((SubscriptionDataRepair) cur, newBundleStartDate, null,
+                                                                                                        ((SubscriptionDataRepair) cur).getEvents(), tenantContext);
                             repairDao.initializeRepair(curOutputRepair.getId(), ((SubscriptionDataRepair) cur).getEvents(), tenantContext);
                             inRepair.add(curOutputRepair);
                             addOnSubscriptionInRepair.add(curOutputRepair);
@@ -237,7 +240,8 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
                 case ADD_ON_REPAIR:
                     // We need to set the baseSubscription as it is useful to calculate addon validity
                     final SubscriptionDataRepair baseSubscription = (SubscriptionDataRepair) subscriptions.get(0);
-                    baseSubscriptionRepair = createSubscriptionDataRepair(baseSubscription, baseSubscription.getBundleStartDate(), baseSubscription.getAlignStartDate(), baseSubscription.getEvents());
+                    baseSubscriptionRepair = createSubscriptionDataRepair(baseSubscription, baseSubscription.getBundleStartDate(), baseSubscription.getAlignStartDate(),
+                                                                          baseSubscription.getEvents(), tenantContext);
                     break;
                 case STANDALONE_REPAIR:
                 default:
@@ -260,7 +264,7 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
             if (dryRun) {
                 baseSubscriptionRepair.addFutureAddonCancellation(addOnSubscriptionInRepair, context);
 
-                final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, convertDataRepair(inRepair));
+                final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, convertDataRepair(inRepair, tenantContext), tenantContext);
                 return createGetBundleRepair(input.getId(), bundle.getExternalKey(), input.getViewId(), repairs);
             } else {
                 dao.repair(bundle.getAccountId(), input.getId(), inRepair, internalCallContextFactory.createInternalCallContext(bundle.getAccountId(), context));
@@ -441,7 +445,7 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
         };
     }
 
-    private List<SubscriptionBaseTimeline> createGetSubscriptionRepairList(final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionBaseTimeline> inRepair) throws CatalogApiException {
+    private List<SubscriptionBaseTimeline> createGetSubscriptionRepairList(final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionBaseTimeline> inRepair, final InternalTenantContext tenantContext) throws CatalogApiException {
 
         final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
         final Set<UUID> repairIds = new TreeSet<UUID>();
@@ -452,17 +456,17 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
 
         for (final SubscriptionBase cur : subscriptions) {
             if (!repairIds.contains(cur.getId())) {
-                result.add(new DefaultSubscriptionBaseTimeline((SubscriptionDataRepair) cur, catalogService.getFullCatalog()));
+                result.add(new DefaultSubscriptionBaseTimeline((SubscriptionDataRepair) cur, catalogService.getFullCatalog(tenantContext)));
             }
         }
 
         return result;
     }
 
-    private List<SubscriptionBaseTimeline> convertDataRepair(final List<SubscriptionDataRepair> input) throws CatalogApiException {
+    private List<SubscriptionBaseTimeline> convertDataRepair(final List<SubscriptionDataRepair> input, final InternalTenantContext tenantContext) throws CatalogApiException {
         final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
         for (final SubscriptionDataRepair cur : input) {
-            result.add(new DefaultSubscriptionBaseTimeline(cur, catalogService.getFullCatalog()));
+            result.add(new DefaultSubscriptionBaseTimeline(cur, catalogService.getFullCatalog(tenantContext)));
         }
 
         return result;
@@ -478,7 +482,8 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
         return null;
     }
 
-    private SubscriptionDataRepair createSubscriptionDataRepair(final DefaultSubscriptionBase curData, final DateTime newBundleStartDate, final DateTime newSubscriptionStartDate, final List<SubscriptionBaseEvent> initialEvents) {
+    private SubscriptionDataRepair createSubscriptionDataRepair(final DefaultSubscriptionBase curData, final DateTime newBundleStartDate, final DateTime newSubscriptionStartDate,
+                                                                final List<SubscriptionBaseEvent> initialEvents, final InternalTenantContext tenantContext) throws CatalogApiException {
         final SubscriptionBuilder builder = new SubscriptionBuilder(curData);
         builder.setActiveVersion(curData.getActiveVersion() + 1);
         if (newBundleStartDate != null) {
@@ -494,7 +499,8 @@ public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase impl
         }
 
         final SubscriptionDataRepair subscriptiondataRepair = new SubscriptionDataRepair(builder, curData.getEvents(), repairApiService, (SubscriptionDao) repairDao, clock, addonUtils, catalogService, internalCallContextFactory);
-        subscriptiondataRepair.rebuildTransitions(curData.getEvents(), catalogService.getFullCatalog());
+        final Catalog fullCatalog = catalogService.getFullCatalog(tenantContext);
+        subscriptiondataRepair.rebuildTransitions(curData.getEvents(), fullCatalog);
         return subscriptiondataRepair;
     }
 
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionDataRepair.java b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionDataRepair.java
index d06c888..e6e1ee9 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionDataRepair.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionDataRepair.java
@@ -24,6 +24,8 @@ import org.joda.time.DateTime;
 
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
+import org.killbill.billing.callcontext.InternalCallContext;
+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.Plan;
@@ -132,7 +134,7 @@ public class SubscriptionDataRepair extends DefaultSubscriptionBase {
         }
     }
 
-    public void addFutureAddonCancellation(final List<SubscriptionDataRepair> addOnSubscriptionInRepair, final CallContext context) {
+    public void addFutureAddonCancellation(final List<SubscriptionDataRepair> addOnSubscriptionInRepair, final CallContext context) throws CatalogApiException {
 
         if (getCategory() != ProductCategory.BASE) {
             return;
@@ -149,7 +151,7 @@ public class SubscriptionDataRepair extends DefaultSubscriptionBase {
     }
 
     private void trickleDownBPEffectForAddon(final List<SubscriptionDataRepair> addOnSubscriptionInRepair, final DateTime effectiveDate, final CallContext context)
-            throws SubscriptionBaseApiException {
+            throws SubscriptionBaseApiException, CatalogApiException {
 
         if (getCategory() != ProductCategory.BASE) {
             return;
@@ -161,7 +163,7 @@ public class SubscriptionDataRepair extends DefaultSubscriptionBase {
     }
 
     private void addAddonCancellationIfRequired(final List<SubscriptionDataRepair> addOnSubscriptionInRepair, final Product baseProduct,
-                                                final DateTime effectiveDate, final CallContext context) {
+                                                final DateTime effectiveDate, final CallContext context) throws CatalogApiException {
 
         final DateTime now = clock.getUTCNow();
         final Iterator<SubscriptionDataRepair> it = addOnSubscriptionInRepair.iterator();
@@ -183,8 +185,10 @@ public class SubscriptionDataRepair extends DefaultSubscriptionBase {
                                                                                 .setEffectiveDate(effectiveDate)
                                                                                 .setRequestedDate(now)
                                                                                 .setFromDisk(true));
-                repairDao.cancelSubscription(cur, cancelEvent, internalCallContextFactory.createInternalCallContext(cur.getId(), ObjectType.SUBSCRIPTION, context), 0);
-                cur.rebuildTransitions(repairDao.getEventsForSubscription(cur.getId(), internalCallContextFactory.createInternalTenantContext(context)), catalogService.getFullCatalog());
+                final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(cur.getId(), ObjectType.SUBSCRIPTION, context);
+                repairDao.cancelSubscription(cur, cancelEvent, internalCallContext, 0);
+                final Catalog fullCatalog = catalogService.getFullCatalog(internalCallContext);
+                cur.rebuildTransitions(repairDao.getEventsForSubscription(cur.getId(), internalCallContextFactory.createInternalTenantContext(context)), fullCatalog);
             }
         }
     }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
index c7d0a18..b9dd7f2 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
@@ -24,6 +24,7 @@ import org.joda.time.DateTime;
 
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
@@ -76,12 +77,12 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
         this.internalCallContextFactory = internalCallContextFactory;
     }
 
-    private SubscriptionBaseEvent createEvent(final boolean firstEvent, final ExistingEvent existingEvent, final DefaultSubscriptionBase subscription, final DateTime transferDate, final CallContext context)
+    private SubscriptionBaseEvent createEvent(final boolean firstEvent, final ExistingEvent existingEvent, final DefaultSubscriptionBase subscription, final DateTime transferDate, final InternalTenantContext context)
             throws CatalogApiException {
 
         SubscriptionBaseEvent newEvent = null;
 
-        final Catalog catalog = catalogService.getFullCatalog();
+        final Catalog catalog = catalogService.getFullCatalog(context);
 
         final DateTime effectiveDate = existingEvent.getEffectiveDate().isBefore(transferDate) ? transferDate : existingEvent.getEffectiveDate();
 
@@ -138,7 +139,7 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
 
     @VisibleForTesting
     List<SubscriptionBaseEvent> toEvents(final List<ExistingEvent> existingEvents, final DefaultSubscriptionBase subscription,
-                                    final DateTime transferDate, final CallContext context) throws SubscriptionBaseTransferApiException {
+                                    final DateTime transferDate, final InternalTenantContext context) throws SubscriptionBaseTransferApiException {
 
         try {
             final List<SubscriptionBaseEvent> result = new LinkedList<SubscriptionBaseEvent>();
@@ -263,9 +264,9 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
                                                                                                             .setCategory(productCategory)
                                                                                                             .setBundleStartDate(effectiveTransferDate)
                                                                                                             .setAlignStartDate(subscriptionAlignStartDate),
-                                                                                                    ImmutableList.<SubscriptionBaseEvent>of());
+                                                                                                    ImmutableList.<SubscriptionBaseEvent>of(), fromInternalCallContext);
 
-                final List<SubscriptionBaseEvent> events = toEvents(existingEvents, defaultSubscriptionBase, effectiveTransferDate, context);
+                final List<SubscriptionBaseEvent> events = toEvents(existingEvents, defaultSubscriptionBase, effectiveTransferDate, fromInternalCallContext);
                 final SubscriptionMigrationData curData = new SubscriptionMigrationData(defaultSubscriptionBase, events, null);
                 subscriptionMigrationDataList.add(curData);
             }
@@ -277,6 +278,8 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
             return bundleMigrationData.getData();
         } catch (SubscriptionBaseRepairException e) {
             throw new SubscriptionBaseTransferApiException(e);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseTransferApiException(e);
         }
     }
 
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index 1d529d5..ec07d4c 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -29,6 +29,7 @@ import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.BillingPeriod;
+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.PhaseType;
@@ -114,7 +115,8 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
         try {
             final String realPriceList = (spec.getPriceListName() == null) ? PriceListSet.DEFAULT_PRICELIST_NAME : spec.getPriceListName();
-            final Plan plan = catalogService.getFullCatalog().findPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, effectiveDate);
+            final InternalTenantContext internalCallContext = createTenantContextFromBundleId(subscription.getBundleId(), context);
+            final Plan plan = catalogService.getFullCatalog(internalCallContext).findPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, effectiveDate);
             final PlanPhase phase = plan.getAllPhases()[0];
             if (phase == null) {
                 throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
@@ -136,14 +138,14 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
 
         try {
-            final List<SubscriptionBaseEvent> events = getEventsOnCreation(subscription.getId(), subscription.getAlignStartDate(), subscription.getBundleStartDate(), subscription.getActiveVersion(),
+            final List<SubscriptionBaseEvent> events = getEventsOnCreation(subscription.getBundleId(), subscription.getId(), subscription.getAlignStartDate(), subscription.getBundleStartDate(), subscription.getActiveVersion(),
                                                                            plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, reCreate, context);
             if (reCreate) {
                 dao.recreateSubscription(subscription, events, internalCallContext);
             } else {
                 dao.createSubscription(subscription, events, internalCallContext);
             }
-            subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
+            subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog(internalCallContext));
         } catch (CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
@@ -167,7 +169,8 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                                                                     subscription.getCurrentPhase().getPhaseType());
 
         try {
-            final BillingActionPolicy policy = catalogService.getFullCatalog().planCancelPolicy(planPhase, now);
+            final InternalTenantContext internalCallContext = createTenantContextFromBundleId(subscription.getBundleId(), context);
+            final BillingActionPolicy policy = catalogService.getFullCatalog(internalCallContext).planCancelPolicy(planPhase, now);
             final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy);
 
             return doCancelPlan(subscription, now, effectiveDate, context);
@@ -200,25 +203,29 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     }
 
     private boolean doCancelPlan(final DefaultSubscriptionBase subscription, final DateTime now, final DateTime effectiveDate, final CallContext context) throws SubscriptionBaseApiException {
-        validateEffectiveDate(subscription, effectiveDate);
-
-        final List<SubscriptionBaseEvent> cancelEvents = getEventsOnCancelPlan(subscription, now, effectiveDate, now, false, context);
-        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
-        // cancelEvents will contain only one item
-        dao.cancelSubscription(subscription, cancelEvents.get(0), internalCallContext, 0);
-        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
+        try {
+            validateEffectiveDate(subscription, effectiveDate);
+
+            final List<SubscriptionBaseEvent> cancelEvents = getEventsOnCancelPlan(subscription, now, effectiveDate, now, false, context);
+            final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
+            // cancelEvents will contain only one item
+            dao.cancelSubscription(subscription, cancelEvents.get(0), internalCallContext, 0);
+            final Catalog fullCatalog = catalogService.getFullCatalog(internalCallContext);
+            subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), fullCatalog);
+
+            if (subscription.getCategory() == ProductCategory.BASE) {
+                final Product baseProduct = (subscription.getState() == EntitlementState.CANCELLED) ? null : subscription.getCurrentPlan().getProduct();
+                cancelAddOnsIfRequired(baseProduct, subscription.getBundleId(), effectiveDate, context);
+            }
 
-        if (subscription.getCategory() == ProductCategory.BASE) {
-            final Product baseProduct = (subscription.getState() == EntitlementState.CANCELLED) ? null : subscription.getCurrentPlan().getProduct();
-            cancelAddOnsIfRequired(baseProduct, subscription.getBundleId(), effectiveDate, context);
+            final boolean isImmediate = subscription.getState() == EntitlementState.CANCELLED;
+            return isImmediate;
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
         }
-
-        final boolean isImmediate = subscription.getState() == EntitlementState.CANCELLED;
-        return isImmediate;
     }
 
-
-        @Override
+    @Override
     public boolean uncancel(final DefaultSubscriptionBase subscription, final CallContext context) throws SubscriptionBaseApiException {
         if (!subscription.isSubscriptionFutureCancelled()) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_UNCANCEL_BAD_STATE, subscription.getId().toString());
@@ -236,7 +243,8 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         final List<SubscriptionBaseEvent> uncancelEvents = new ArrayList<SubscriptionBaseEvent>();
         uncancelEvents.add(uncancelEvent);
 
-        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now);
+        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
+        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now, internalCallContext);
         final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                                           PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(), nextTimedPhase.getPhase().getName(), now, nextTimedPhase.getStartPhase()) :
                                           null;
@@ -244,11 +252,14 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
             uncancelEvents.add(nextPhaseEvent);
         }
 
-        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
         dao.uncancelSubscription(subscription, uncancelEvents, internalCallContext);
-        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
-
-        return true;
+        try {
+            final Catalog fullCatalog = catalogService.getFullCatalog(internalCallContext);
+            subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), fullCatalog);
+            return true;
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
     }
 
     @Override
@@ -258,7 +269,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
         validateEntitlementState(subscription);
 
-        final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, productName, term, priceList, now);
+        final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, productName, term, priceList, now, context);
         final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(planChangeResult.getPolicy());
         validateEffectiveDate(subscription, effectiveDate);
 
@@ -304,10 +315,11 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
     @Override
     public PlanChangeResult getPlanChangeResult(final DefaultSubscriptionBase subscription, final String productName,
-                                                final BillingPeriod term, final String priceList, final DateTime effectiveDate) throws SubscriptionBaseApiException {
+                                                final BillingPeriod term, final String priceList, final DateTime effectiveDate, final TenantContext context) throws SubscriptionBaseApiException {
         final PlanChangeResult planChangeResult;
         try {
-            final Product destProduct = catalogService.getFullCatalog().findProduct(productName, effectiveDate);
+            final InternalTenantContext internalCallContext = createTenantContextFromBundleId(subscription.getBundleId(), context);
+            final Product destProduct = catalogService.getFullCatalog(internalCallContext).findProduct(productName, effectiveDate);
             final Plan currentPlan = subscription.getCurrentPlan();
             final PriceList currentPriceList = subscription.getCurrentPriceList();
             final PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
@@ -320,7 +332,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                                                                 term,
                                                                 priceList);
 
-            planChangeResult = catalogService.getFullCatalog().planChange(fromPlanPhase, toPlanPhase, effectiveDate);
+            planChangeResult = catalogService.getFullCatalog(internalCallContext).planChange(fromPlanPhase, toPlanPhase, effectiveDate);
         } catch (CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
@@ -336,12 +348,12 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                                   final DateTime effectiveDate,
                                   final CallContext context) throws SubscriptionBaseApiException, CatalogApiException {
 
-        final Plan newPlan = catalogService.getFullCatalog().findPlan(newProductName, newBillingPeriod, newPriceList, effectiveDate, subscription.getStartDate());
+        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
+        final Plan newPlan = catalogService.getFullCatalog(internalCallContext).findPlan(newProductName, newBillingPeriod, newPriceList, effectiveDate, subscription.getStartDate());
 
         final List<SubscriptionBaseEvent> changeEvents = getEventsOnChangePlan(subscription, newPlan, newPriceList, now, effectiveDate, now, false, context);
-        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
         dao.changePlan(subscription, changeEvents, internalCallContext);
-        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
+        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog(internalCallContext));
 
         if (subscription.getCategory() == ProductCategory.BASE) {
             final Product baseProduct = (subscription.getState() == EntitlementState.CANCELLED) ? null : subscription.getCurrentPlan().getProduct();
@@ -351,12 +363,14 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     }
 
     @Override
-    public List<SubscriptionBaseEvent> getEventsOnCreation(final UUID subscriptionId, final DateTime alignStartDate, final DateTime bundleStartDate, final long activeVersion,
+    public List<SubscriptionBaseEvent> getEventsOnCreation(final UUID bundleId, final UUID subscriptionId, final DateTime alignStartDate, final DateTime bundleStartDate, final long activeVersion,
                                                            final Plan plan, final PhaseType initialPhase,
                                                            final String realPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
                                                            final boolean reCreate, final TenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
+
+        final InternalTenantContext internalTenantContext = createTenantContextFromBundleId(bundleId, context);
         final TimedPhase[] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(alignStartDate, bundleStartDate, plan, initialPhase,
-                                                                                              realPriceList, requestedDate, effectiveDate);
+                                                                                              realPriceList, requestedDate, effectiveDate, internalTenantContext);
 
         final ApiEventBuilder createBuilder = new ApiEventBuilder()
                 .setSubscriptionId(subscriptionId)
@@ -388,7 +402,8 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                                                              final String newPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
                                                              final boolean addCancellationAddOnForEventsIfRequired, final TenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
 
-        final TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(subscription, newPlan, newPriceList, requestedDate, effectiveDate);
+        final InternalTenantContext internalTenantContext = createTenantContextFromBundleId(subscription.getBundleId(), context);
+        final TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(subscription, newPlan, newPriceList, requestedDate, effectiveDate, internalTenantContext);
 
         final SubscriptionBaseEvent changeEvent = new ApiEventChange(new ApiEventBuilder()
                                                                              .setSubscriptionId(subscription.getId())
@@ -401,7 +416,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                                                                              .setRequestedDate(requestedDate)
                                                                              .setFromDisk(true));
 
-        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, newPriceList, processedDate, effectiveDate);
+        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, newPriceList, processedDate, effectiveDate, internalTenantContext);
         final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                                           PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(),
                                                                               nextTimedPhase.getPhase().getName(), processedDate, nextTimedPhase.getStartPhase()) :
@@ -424,7 +439,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     @Override
     public List<SubscriptionBaseEvent> getEventsOnCancelPlan(final DefaultSubscriptionBase subscription,
                                                              final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
-                                                             final boolean addCancellationAddOnForEventsIfRequired, final TenantContext context) {
+                                                             final boolean addCancellationAddOnForEventsIfRequired, final TenantContext context) throws CatalogApiException {
 
         final List<SubscriptionBaseEvent> cancelEvents = new ArrayList<SubscriptionBaseEvent>();
         final SubscriptionBaseEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
@@ -443,7 +458,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     }
 
 
-    public int cancelAddOnsIfRequired(final Product baseProduct, final UUID bundleId, final DateTime effectiveDate, final CallContext context) {
+    public int cancelAddOnsIfRequired(final Product baseProduct, final UUID bundleId, final DateTime effectiveDate, final CallContext context) throws CatalogApiException {
 
         // If cancellation/change occur in the future, there is nothing to do
         final DateTime now = clock.getUTCNow();
@@ -461,7 +476,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     }
 
     private List<DefaultSubscriptionBase> addCancellationAddOnForEventsIfRequired(final List<SubscriptionBaseEvent> events, final Product baseProduct, final UUID bundleId,
-                                                                                  final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate, final TenantContext context) {
+                                                                                  final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate, final TenantContext context) throws CatalogApiException {
 
         final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = new ArrayList<DefaultSubscriptionBase>();
 
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
index 83dcac1..2f0a3e4 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
@@ -17,21 +17,21 @@
 package org.killbill.billing.subscription.engine.addon;
 
 import org.joda.time.DateTime;
-
 import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
-import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
-import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
 
 import com.google.inject.Inject;
 
 public class AddonUtils {
+
     private final CatalogService catalogService;
 
     @Inject
@@ -49,27 +49,27 @@ public class AddonUtils {
         final Product baseProduct = baseSubscription.getCurrentPlan().getProduct();
         if (isAddonIncluded(baseProduct, targetAddOnPlan)) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_ALREADY_INCLUDED,
-                                                  targetAddOnPlan.getName(), baseSubscription.getCurrentPlan().getProduct().getName());
+                                                   targetAddOnPlan.getName(), baseSubscription.getCurrentPlan().getProduct().getName());
         }
 
         if (!isAddonAvailable(baseProduct, targetAddOnPlan)) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_NOT_AVAILABLE,
-                                                  targetAddOnPlan.getName(), baseSubscription.getCurrentPlan().getProduct().getName());
+                                                   targetAddOnPlan.getName(), baseSubscription.getCurrentPlan().getProduct().getName());
         }
     }
 
-    public boolean isAddonAvailableFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+    public boolean isAddonAvailableFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan, final InternalTenantContext context) {
         try {
-            final Product product = catalogService.getFullCatalog().findProduct(baseProductName, requestedDate);
+            final Product product = catalogService.getFullCatalog(context).findProduct(baseProductName, requestedDate);
             return isAddonAvailable(product, targetAddOnPlan);
         } catch (CatalogApiException e) {
             throw new SubscriptionBaseError(e);
         }
     }
 
-    public boolean isAddonAvailableFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+    public boolean isAddonAvailableFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan, final InternalTenantContext context) {
         try {
-            final Plan plan = catalogService.getFullCatalog().findPlan(basePlanName, requestedDate);
+            final Plan plan = catalogService.getFullCatalog(context).findPlan(basePlanName, requestedDate);
             final Product product = plan.getProduct();
             return isAddonAvailable(product, targetAddOnPlan);
         } catch (CatalogApiException e) {
@@ -89,9 +89,9 @@ public class AddonUtils {
         return false;
     }
 
-    public boolean isAddonIncludedFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+    public boolean isAddonIncludedFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan, final InternalTenantContext context) {
         try {
-            final Product product = catalogService.getFullCatalog().findProduct(baseProductName, requestedDate);
+            final Product product = catalogService.getFullCatalog(context).findProduct(baseProductName, requestedDate);
             return isAddonIncluded(product, targetAddOnPlan);
         } catch (CatalogApiException e) {
             throw new SubscriptionBaseError(e);
@@ -99,9 +99,9 @@ public class AddonUtils {
 
     }
 
-    public boolean isAddonIncludedFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+    public boolean isAddonIncludedFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan, final InternalTenantContext context) {
         try {
-            final Plan plan = catalogService.getFullCatalog().findPlan(basePlanName, requestedDate);
+            final Plan plan = catalogService.getFullCatalog(context).findPlan(basePlanName, requestedDate);
             final Product product = plan.getProduct();
             return isAddonIncluded(product, targetAddOnPlan);
         } catch (CatalogApiException e) {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
index 8178614..d91b31f 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
@@ -23,6 +23,7 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -158,28 +159,29 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
             return;
         }
 
-        final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(event.getSubscriptionId(), context);
-        if (subscription == null) {
-            log.warn("Failed to retrieve subscription for id %s", event.getSubscriptionId());
-            return;
-        }
-        if (subscription.getActiveVersion() > event.getActiveVersion()) {
-            // Skip repaired events
-            return;
-        }
-
-        //
-        // Do any internal processing on that event before we send the event to the bus
-        //
-        int theRealSeqId = seqId;
-        if (event.getType() == EventType.PHASE) {
-            onPhaseEvent(subscription, context);
-        } else if (event.getType() == EventType.API_USER && subscription.getCategory() == ProductCategory.BASE) {
-            final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
-            theRealSeqId = onBasePlanEvent(subscription, (ApiEvent) event, context.toCallContext(tenantId));
-        }
 
         try {
+            final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(event.getSubscriptionId(), context);
+            if (subscription == null) {
+                log.warn("Failed to retrieve subscription for id %s", event.getSubscriptionId());
+                return;
+            }
+            if (subscription.getActiveVersion() > event.getActiveVersion()) {
+                // Skip repaired events
+                return;
+            }
+
+            //
+            // Do any internal processing on that event before we send the event to the bus
+            //
+            int theRealSeqId = seqId;
+            if (event.getType() == EventType.PHASE) {
+                onPhaseEvent(subscription, context);
+            } else if (event.getType() == EventType.API_USER && subscription.getCategory() == ProductCategory.BASE) {
+                final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+                theRealSeqId = onBasePlanEvent(subscription, (ApiEvent) event, context.toCallContext(tenantId));
+            }
+
             final SubscriptionBaseTransitionData transition = (subscription.getTransitionFromEvent(event, theRealSeqId));
             final EffectiveSubscriptionInternalEvent busEvent = new DefaultEffectiveSubscriptionEvent(transition, subscription.getAlignStartDate(),
                                                                                                       context.getUserToken(),
@@ -187,13 +189,15 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
             eventBus.post(busEvent);
         } catch (EventBusException e) {
             log.warn("Failed to post subscription event " + event, e);
+        } catch (CatalogApiException e) {
+            log.warn("Failed to post subscription event " + event, e);
         }
     }
 
     private void onPhaseEvent(final DefaultSubscriptionBase subscription, final InternalCallContext context) {
         try {
             final DateTime now = clock.getUTCNow();
-            final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now);
+            final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now, context);
             final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                                               PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(),
                                                                                   nextTimedPhase.getPhase().getName(), now, nextTimedPhase.getStartPhase()) :
@@ -206,7 +210,7 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
         }
     }
 
-    private int onBasePlanEvent(final DefaultSubscriptionBase baseSubscription, final ApiEvent event, final CallContext context) {
+    private int onBasePlanEvent(final DefaultSubscriptionBase baseSubscription, final ApiEvent event, final CallContext context) throws CatalogApiException {
         final Product baseProduct = (baseSubscription.getState() == EntitlementState.CANCELLED) ? null : baseSubscription.getCurrentPlan().getProduct();
         return apiService.cancelAddOnsIfRequired(baseProduct, baseSubscription.getBundleId(), event.getEffectiveDate(), context);
     }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index 7aa2fd9..6dbce20 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -33,6 +33,8 @@ import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import org.joda.time.DateTime;
+import org.killbill.billing.catalog.api.Catalog;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -288,12 +290,12 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     @Override
-    public SubscriptionBase getBaseSubscription(final UUID bundleId, final InternalTenantContext context) {
+    public SubscriptionBase getBaseSubscription(final UUID bundleId, final InternalTenantContext context) throws CatalogApiException {
         return getBaseSubscription(bundleId, true, context);
     }
 
     @Override
-    public SubscriptionBase getSubscriptionFromId(final UUID subscriptionId, final InternalTenantContext context) {
+    public SubscriptionBase getSubscriptionFromId(final UUID subscriptionId, final InternalTenantContext context) throws CatalogApiException {
         final SubscriptionBase shellSubscription = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<SubscriptionBase>() {
             @Override
             public SubscriptionBase inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -305,7 +307,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     @Override
-    public List<SubscriptionBase> getSubscriptions(final UUID bundleId, final List<SubscriptionBaseEvent> dryRunEvents, final InternalTenantContext context) {
+    public List<SubscriptionBase> getSubscriptions(final UUID bundleId, final List<SubscriptionBaseEvent> dryRunEvents, final InternalTenantContext context) throws CatalogApiException {
         return buildBundleSubscriptions(getSubscriptionFromBundleId(bundleId, context), null, dryRunEvents, context);
     }
 
@@ -325,7 +327,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     @Override
-    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final InternalTenantContext context) {
+    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final InternalTenantContext context) throws CatalogApiException {
         final Map<UUID, List<SubscriptionBase>> subscriptionsFromAccountId = getSubscriptionsFromAccountId(context);
 
         final List<SubscriptionBaseEvent> eventsForAccount = getEventsForAccountId(context);
@@ -812,7 +814,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         }
     }
 
-    private SubscriptionBase buildSubscription(final SubscriptionBase input, final InternalTenantContext context) {
+    private SubscriptionBase buildSubscription(final SubscriptionBase input, final InternalTenantContext context) throws CatalogApiException {
 
         if (input == null) {
             return null;
@@ -842,7 +844,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
 
     private List<SubscriptionBase> buildBundleSubscriptions(final List<SubscriptionBase> input, @Nullable final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscription,
-                                                            @Nullable List<SubscriptionBaseEvent> dryRunEvents, final InternalTenantContext context) {
+                                                            @Nullable List<SubscriptionBaseEvent> dryRunEvents, final InternalTenantContext context) throws CatalogApiException {
         if (input == null || input.size() == 0) {
             return Collections.emptyList();
         }
@@ -870,7 +872,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
                                                        getEventsForSubscription(cur.getId(), context);
             mergeDryRunEvents(cur.getId(), events, dryRunEvents);
 
-            SubscriptionBase reloaded = createSubscriptionForInternalUse(cur, events);
+            SubscriptionBase reloaded = createSubscriptionForInternalUse(cur, events, context);
 
             switch (cur.getCategory()) {
                 case BASE:
@@ -891,8 +893,8 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
                     final boolean createCancelEvent = (futureBaseEvent != null && targetAddOnPlan != null) &&
                                                       ((futureBaseEvent instanceof ApiEventCancel) ||
-                                                       ((!addonUtils.isAddonAvailableFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
-                                                        (addonUtils.isAddonIncludedFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
+                                                       ((!addonUtils.isAddonAvailableFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan, context)) ||
+                                                        (addonUtils.isAddonIncludedFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan, context))));
 
                     if (createCancelEvent && reloaded.getFutureEndDate() == null) {
                         final DateTime now = clock.getUTCNow();
@@ -909,7 +911,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
 
                         events.add(addOnCancelEvent);
                         // Finally reload subscription with full set of events
-                        reloaded = createSubscriptionForInternalUse(cur, events);
+                        reloaded = createSubscriptionForInternalUse(cur, events, context);
                     }
                     break;
                 default:
@@ -1028,15 +1030,16 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         });
     }
 
-    private DefaultSubscriptionBase createSubscriptionForInternalUse(final SubscriptionBase shellSubscription, final List<SubscriptionBaseEvent> events) {
+    private DefaultSubscriptionBase createSubscriptionForInternalUse(final SubscriptionBase shellSubscription, final List<SubscriptionBaseEvent> events, final InternalTenantContext context) throws CatalogApiException {
         final DefaultSubscriptionBase result = new DefaultSubscriptionBase(new SubscriptionBuilder(((DefaultSubscriptionBase) shellSubscription)), null, clock);
         if (events.size() > 0) {
-            result.rebuildTransitions(events, catalogService.getFullCatalog());
+            final Catalog fullCatalog = catalogService.getFullCatalog(context);
+            result.rebuildTransitions(events, fullCatalog);
         }
         return result;
     }
 
-    private SubscriptionBase getBaseSubscription(final UUID bundleId, final boolean rebuildSubscription, final InternalTenantContext context) {
+    private SubscriptionBase getBaseSubscription(final UUID bundleId, final boolean rebuildSubscription, final InternalTenantContext context) throws CatalogApiException {
         final List<SubscriptionBase> subscriptions = getSubscriptionFromBundleId(bundleId, context);
         for (final SubscriptionBase cur : subscriptions) {
             if (cur.getCategory() == ProductCategory.BASE) {
@@ -1069,7 +1072,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     private void notifyBusOfEffectiveImmediateChange(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final DefaultSubscriptionBase subscription,
                                                      final SubscriptionBaseEvent immediateEvent, final int seqId, final InternalCallContext context) {
         try {
-            final DefaultSubscriptionBase upToDateSubscription = createSubscriptionWithNewEvent(subscription, immediateEvent);
+            final DefaultSubscriptionBase upToDateSubscription = createSubscriptionWithNewEvent(subscription, immediateEvent, context);
 
             final SubscriptionBaseTransitionData transition = upToDateSubscription.getTransitionFromEvent(immediateEvent, seqId);
             final EffectiveSubscriptionInternalEvent busEvent = new DefaultEffectiveSubscriptionEvent(transition, upToDateSubscription.getAlignStartDate(),
@@ -1079,6 +1082,8 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
             eventBus.postFromTransaction(busEvent, entitySqlDaoWrapperFactory.getSqlDao());
         } catch (EventBusException e) {
             log.warn("Failed to post effective event for subscription " + subscription.getId(), e);
+        } catch (CatalogApiException e) {
+            log.warn("Failed to post effective event for subscription " + subscription.getId(), e);
         }
     }
 
@@ -1140,7 +1145,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     //
     // Creates a copy of the existing subscriptions whose 'transitions' will reflect the new event
     //
-    private DefaultSubscriptionBase createSubscriptionWithNewEvent(final DefaultSubscriptionBase subscription, SubscriptionBaseEvent newEvent) {
+    private DefaultSubscriptionBase createSubscriptionWithNewEvent(final DefaultSubscriptionBase subscription, SubscriptionBaseEvent newEvent, final InternalTenantContext context) throws CatalogApiException {
 
         final DefaultSubscriptionBase subscriptionWithNewEvent = new DefaultSubscriptionBase(subscription, null, clock);
         final List<SubscriptionBaseEvent> allEvents = new LinkedList<SubscriptionBaseEvent>();
@@ -1148,7 +1153,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
             allEvents.addAll(subscriptionWithNewEvent.getEvents());
         }
         allEvents.add(newEvent);
-        subscriptionWithNewEvent.rebuildTransitions(allEvents, catalogService.getFullCatalog());
+        subscriptionWithNewEvent.rebuildTransitions(allEvents, catalogService.getFullCatalog(context));
         return subscriptionWithNewEvent;
     }
 
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
index 45901e9..78aa6af 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
@@ -22,6 +22,7 @@ import java.util.UUID;
 
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.entitlement.api.SubscriptionApiException;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.migration.AccountMigrationData;
@@ -53,17 +54,17 @@ public interface SubscriptionDao extends EntityDao<SubscriptionBundleModelDao, S
 
     public SubscriptionBaseBundle createSubscriptionBundle(DefaultSubscriptionBaseBundle bundle, InternalCallContext context);
 
-    public SubscriptionBase getSubscriptionFromId(UUID subscriptionId, InternalTenantContext context);
+    public SubscriptionBase getSubscriptionFromId(UUID subscriptionId, InternalTenantContext context) throws CatalogApiException;
 
     // ACCOUNT retrieval
     public UUID getAccountIdFromSubscriptionId(UUID subscriptionId, InternalTenantContext context);
 
     // SubscriptionBase retrieval
-    public SubscriptionBase getBaseSubscription(UUID bundleId, InternalTenantContext context);
+    public SubscriptionBase getBaseSubscription(UUID bundleId, InternalTenantContext context) throws CatalogApiException;
 
-    public List<SubscriptionBase> getSubscriptions(UUID bundleId, List<SubscriptionBaseEvent> dryRunEvents, InternalTenantContext context);
+    public List<SubscriptionBase> getSubscriptions(UUID bundleId, List<SubscriptionBaseEvent> dryRunEvents, InternalTenantContext context) throws CatalogApiException;
 
-    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(InternalTenantContext context);
+    public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(InternalTenantContext context) throws CatalogApiException;
 
     // Update
     public void updateChargedThroughDate(DefaultSubscriptionBase subscription, InternalCallContext context);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java b/subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java
index e29a18f..75172ff 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java
@@ -85,7 +85,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
         Assert.assertEquals(phases[1].getStartPhase(), defaultSubscriptionBase.getBundleStartDate().plusDays(30));
 
         // Verify the next phase via the other API
-        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, effectiveDate);
+        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, effectiveDate, internalCallContext);
         Assert.assertEquals(nextTimePhase.getStartPhase(), defaultSubscriptionBase.getBundleStartDate().plusDays(30));
 
         // Now look at the past, before the bundle started
@@ -96,7 +96,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
 
         // Verify the next phase via the other API
         try {
-            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, effectiveDateInThePast);
+            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, effectiveDateInThePast, internalCallContext);
             Assert.fail("Can't use getNextTimedPhase(): the effective date is before the initial plan");
         } catch (SubscriptionBaseError e) {
             Assert.assertTrue(true);
@@ -130,7 +130,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
         Assert.assertEquals(phases[1].getStartPhase(), defaultSubscriptionBase.getStartDate().plusMonths(1));
 
         // Verify the next phase via the other API
-        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, effectiveDate);
+        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, effectiveDate, internalCallContext);
         Assert.assertEquals(nextTimePhase.getStartPhase(), defaultSubscriptionBase.getStartDate().plusMonths(1));
 
         // Now look at the past, before the subscription started
@@ -141,7 +141,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
 
         // Verify the next phase via the other API
         try {
-            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, effectiveDateInThePast);
+            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, effectiveDateInThePast, internalCallContext);
             Assert.fail("Can't use getNextTimedPhase(): the effective date is before the initial plan");
         } catch (SubscriptionBaseError e) {
             Assert.assertTrue(true);
@@ -160,7 +160,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
         Assert.assertNull(newPhase);
     }
 
-    private DefaultSubscriptionBase createSubscriptionStartedInThePast(final String productName, final PhaseType phaseType) {
+    private DefaultSubscriptionBase createSubscriptionStartedInThePast(final String productName, final PhaseType phaseType) throws CatalogApiException {
         final SubscriptionBuilder builder = new SubscriptionBuilder();
         builder.setBundleStartDate(clock.getUTCNow().minusHours(10));
         // Make sure to set the dates apart
@@ -173,7 +173,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
                                                                     phaseType,
                                                                     ApiEventType.CREATE,
                                                                     defaultSubscriptionBase.getActiveVersion());
-        defaultSubscriptionBase.rebuildTransitions(ImmutableList.<SubscriptionBaseEvent>of(event), catalogService.getFullCatalog());
+        defaultSubscriptionBase.rebuildTransitions(ImmutableList.<SubscriptionBaseEvent>of(event), catalogService.getFullCatalog(internalCallContext));
 
         Assert.assertEquals(defaultSubscriptionBase.getAllTransitions().size(), 1);
         Assert.assertNull(defaultSubscriptionBase.getAllTransitions().get(0).getPreviousPhase());
@@ -186,7 +186,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
                                     final DefaultSubscriptionBase defaultSubscriptionBase,
                                     final String previousProductName,
                                     final String newProductName,
-                                    final PhaseType commonPhaseType) {
+                                    final PhaseType commonPhaseType) throws CatalogApiException {
         final SubscriptionBaseEvent previousEvent = createSubscriptionEvent(defaultSubscriptionBase.getStartDate(),
                                                                             previousProductName,
                                                                             commonPhaseType,
@@ -198,7 +198,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
                                                                     ApiEventType.CHANGE,
                                                                     defaultSubscriptionBase.getActiveVersion());
 
-        defaultSubscriptionBase.rebuildTransitions(ImmutableList.<SubscriptionBaseEvent>of(previousEvent, event), catalogService.getFullCatalog());
+        defaultSubscriptionBase.rebuildTransitions(ImmutableList.<SubscriptionBaseEvent>of(previousEvent, event), catalogService.getFullCatalog(internalCallContext));
 
         final List<SubscriptionBaseTransition> newTransitions = defaultSubscriptionBase.getAllTransitions();
         Assert.assertEquals(newTransitions.size(), 2);
@@ -230,9 +230,9 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
                                                  final String newProductName,
                                                  final DateTime effectiveChangeDate) throws CatalogApiException, SubscriptionBaseApiException {
         // The date is used for different catalog versions - we don't care here
-        final Plan newPlan = catalogService.getFullCatalog().findPlan(newProductName, clock.getUTCNow());
+        final Plan newPlan = catalogService.getFullCatalog(internalCallContext).findPlan(newProductName, clock.getUTCNow());
 
-        return planAligner.getNextTimedPhaseOnChange(defaultSubscriptionBase, newPlan, priceList, effectiveChangeDate, effectiveChangeDate);
+        return planAligner.getNextTimedPhaseOnChange(defaultSubscriptionBase, newPlan, priceList, effectiveChangeDate, effectiveChangeDate, internalCallContext);
     }
 
     private TimedPhase[] getTimedPhasesOnCreate(final String productName,
@@ -240,10 +240,11 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
                                                 final DefaultSubscriptionBase defaultSubscriptionBase,
                                                 final DateTime effectiveDate) throws CatalogApiException, SubscriptionBaseApiException {
         // The date is used for different catalog versions - we don't care here
-        final Plan plan = catalogService.getFullCatalog().findPlan(productName, clock.getUTCNow());
+        final Plan plan = catalogService.getFullCatalog(internalCallContext).findPlan(productName, clock.getUTCNow());
 
         // Same here for the requested date
-        final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(defaultSubscriptionBase.getAlignStartDate(), defaultSubscriptionBase.getBundleStartDate(), plan, initialPhase, priceList, clock.getUTCNow(), effectiveDate);
+        final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(defaultSubscriptionBase.getAlignStartDate(), defaultSubscriptionBase.getBundleStartDate(),
+                                                                                    plan, initialPhase, priceList, clock.getUTCNow(), effectiveDate, internalCallContext);
         Assert.assertEquals(phases.length, 2);
 
         return phases;
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
index f4c88b8..d651c1b 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
@@ -79,7 +79,7 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
         final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(subscriptionBuilder);
 
         final DateTime transferDate = subscriptionStartTime.plusDays(10);
-        final List<SubscriptionBaseEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
+        final List<SubscriptionBaseEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, internalCallContext);
 
         Assert.assertEquals(events.size(), 0);
     }
@@ -94,7 +94,7 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
         final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(subscriptionBuilder);
 
         final DateTime transferDate = subscriptionStartTime.plusHours(1);
-        final List<SubscriptionBaseEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
+        final List<SubscriptionBaseEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, internalCallContext);
 
         Assert.assertEquals(events.size(), 1);
         Assert.assertEquals(events.get(0).getType(), EventType.API_USER);
@@ -164,7 +164,7 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
         final SubscriptionBuilder subscriptionBuilder = new SubscriptionBuilder();
         final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(subscriptionBuilder);
 
-        return transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
+        return transferApi.toEvents(existingEvents, subscription, transferDate, internalCallContext);
     }
 
     private ExistingEvent createEvent(final DateTime eventEffectiveDate, final SubscriptionBaseTransitionType subscriptionTransitionType) {
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java b/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
index aefb6fb..63518ba 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
@@ -25,6 +25,7 @@ import org.joda.time.DateTimeZone;
 import org.killbill.billing.account.api.AccountData;
 import org.killbill.billing.api.TestApiListener;
 import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.DefaultCatalogService;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogService;
@@ -50,10 +51,10 @@ public class DefaultSubscriptionTestInitializer implements SubscriptionTestIniti
     public DefaultSubscriptionTestInitializer() {
     }
 
-    public Catalog initCatalog(final CatalogService catalogService) throws Exception {
+    public Catalog initCatalog(final CatalogService catalogService, final InternalTenantContext context) throws Exception {
 
         ((DefaultCatalogService) catalogService).loadCatalog();
-        final Catalog catalog = catalogService.getFullCatalog();
+        final Catalog catalog = catalogService.getFullCatalog(context);
         assertNotNull(catalog);
         return catalog;
     }
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
index ce52349..3454053 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
@@ -27,6 +27,7 @@ import java.util.TreeSet;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -286,7 +287,11 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
     private SubscriptionBase buildSubscription(final DefaultSubscriptionBase in, final InternalTenantContext context) {
         final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(new SubscriptionBuilder(in), null, clock);
         if (events.size() > 0) {
-            subscription.rebuildTransitions(getEventsForSubscription(in.getId(), context), catalogService.getFullCatalog());
+            try {
+                subscription.rebuildTransitions(getEventsForSubscription(in.getId(), context), catalogService.getFullCatalog(context));
+            } catch (CatalogApiException e) {
+                e.printStackTrace();
+            }
         }
         return subscription;
 
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModule.java b/subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModule.java
index 9d6cc96..495e447 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModule.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModule.java
@@ -21,6 +21,7 @@ package org.killbill.billing.subscription.glue;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.api.TestApiListener;
 import org.killbill.billing.catalog.glue.CatalogModule;
+import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.subscription.DefaultSubscriptionTestInitializer;
 import org.killbill.billing.subscription.SubscriptionTestInitializer;
@@ -41,6 +42,7 @@ public class TestDefaultSubscriptionModule extends DefaultSubscriptionModule {
         install(new CatalogModule(configSource));
         install(new CallContextModule(configSource));
         install(new CacheModule(configSource));
+        install(new MockTenantModule(configSource));
 
         bind(AccountUserApi.class).toInstance(Mockito.mock(AccountUserApi.class));
 
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestInitializer.java b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestInitializer.java
index 9fba4e7..6feee72 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestInitializer.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestInitializer.java
@@ -21,6 +21,7 @@ package org.killbill.billing.subscription;
 import org.killbill.billing.account.api.AccountData;
 import org.killbill.billing.api.TestApiListener;
 import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogService;
 import org.killbill.billing.lifecycle.api.BusService;
@@ -31,7 +32,7 @@ import org.killbill.clock.ClockMock;
 
 public interface SubscriptionTestInitializer {
 
-    public Catalog initCatalog(final CatalogService catalogService) throws Exception;
+    public Catalog initCatalog(final CatalogService catalogService, final InternalTenantContext context) throws Exception;
 
     public AccountData initAccountData();
 
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
index a099dc0..dbb011d 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
@@ -116,7 +116,7 @@ public class SubscriptionTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
 
         subscriptionTestInitializer.startTestFamework(testListener, clock, busService, subscriptionBaseService);
 
-        this.catalog = subscriptionTestInitializer.initCatalog(catalogService);
+        this.catalog = subscriptionTestInitializer.initCatalog(catalogService, internalCallContext);
         this.accountData = subscriptionTestInitializer.initAccountData();
         this.bundle = subscriptionTestInitializer.initBundle(subscriptionInternalApi, internalCallContext);
     }
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
index a1cfc8e..9539fc7 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
@@ -105,7 +105,7 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
         super.beforeMethod();
         subscriptionTestInitializer.startTestFamework(testListener, clock, busService, subscriptionBaseService);
 
-        this.catalog = subscriptionTestInitializer.initCatalog(catalogService);
+        this.catalog = subscriptionTestInitializer.initCatalog(catalogService, internalCallContext);
         this.accountData = subscriptionTestInitializer.initAccountData();
         this.bundle = subscriptionTestInitializer.initBundle(subscriptionInternalApi, internalCallContext);
 
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java b/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
new file mode 100644
index 0000000..50d1b7b
--- /dev/null
+++ b/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.tenant.api;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.tenant.api.TenantKV.TenantKey;
+import org.killbill.billing.tenant.dao.TenantDao;
+
+public class DefaultTenantInternalApi implements TenantInternalApi {
+
+    private final TenantDao tenantDao;
+
+    @Inject
+    public DefaultTenantInternalApi(final TenantDao tenantDao) {
+        this.tenantDao = tenantDao;
+    }
+
+    @Override
+    public List<String> getTenantCatalogs(final InternalTenantContext tenantContext) throws TenantApiException {
+        return tenantDao.getTenantValueForKey(TenantKey.CATALOG.toString(), tenantContext);
+    }
+}
diff --git a/tenant/src/main/resources/org/killbill/billing/tenant/ddl.sql b/tenant/src/main/resources/org/killbill/billing/tenant/ddl.sql
index 40d439a..a95ec39 100644
--- a/tenant/src/main/resources/org/killbill/billing/tenant/ddl.sql
+++ b/tenant/src/main/resources/org/killbill/billing/tenant/ddl.sql
@@ -23,8 +23,8 @@ CREATE TABLE tenant_kvs (
    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
    id char(36) NOT NULL,
    tenant_record_id int(11) unsigned default null,
-   tenant_key varchar(64) NOT NULL,
-   tenant_value varchar(1024) NOT NULL,
+   tenant_key varchar(256) NOT NULL,
+   tenant_value mediumtext NOT NULL,
    is_active bool DEFAULT 1,
    created_date datetime NOT NULL,
    created_by varchar(50) NOT NULL,
diff --git a/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModule.java b/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModule.java
index a787d5e..3fba86d 100644
--- a/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModule.java
+++ b/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModule.java
@@ -22,7 +22,7 @@ import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.util.glue.CacheModule;
 import org.killbill.billing.util.glue.CallContextModule;
 
-public class TestTenantModule extends TenantModule {
+public class TestTenantModule extends DefaultTenantModule {
 
     public TestTenantModule(final KillbillConfigSource configSource) {
         super(configSource);
diff --git a/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModuleNoDB.java b/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModuleNoDB.java
index 7d240aa..aacb5ab 100644
--- a/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModuleNoDB.java
+++ b/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModuleNoDB.java
@@ -21,6 +21,8 @@ package org.killbill.billing.tenant.glue;
 import org.killbill.billing.GuicyKillbillTestNoDBModule;
 import org.killbill.billing.mock.glue.MockNonEntityDaoModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.tenant.dao.DefaultTenantDao;
+import org.killbill.billing.tenant.dao.TenantDao;
 
 public class TestTenantModuleNoDB extends TestTenantModule {
 
diff --git a/usage/src/test/java/org/killbill/billing/usage/glue/TestUsageModule.java b/usage/src/test/java/org/killbill/billing/usage/glue/TestUsageModule.java
index 78a0882..3273c3b 100644
--- a/usage/src/test/java/org/killbill/billing/usage/glue/TestUsageModule.java
+++ b/usage/src/test/java/org/killbill/billing/usage/glue/TestUsageModule.java
@@ -18,6 +18,7 @@
 
 package org.killbill.billing.usage.glue;
 
+import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.usage.api.UsageUserApi;
 import org.killbill.billing.usage.api.user.MockUsageUserApi;
@@ -36,6 +37,7 @@ public class TestUsageModule extends UsageModule {
     protected void installUsageUserApi() {
         bind(MockUsageUserApi.class).asEagerSingleton();
         bind(UsageUserApi.class).to(MockUsageUserApi.class).asEagerSingleton();
+        install(new MockTenantModule(configSource));
     }
 
 }
diff --git a/util/src/test/java/org/killbill/billing/mock/glue/MockTenantModule.java b/util/src/test/java/org/killbill/billing/mock/glue/MockTenantModule.java
new file mode 100644
index 0000000..0983b74
--- /dev/null
+++ b/util/src/test/java/org/killbill/billing/mock/glue/MockTenantModule.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.mock.glue;
+
+import org.killbill.billing.glue.TenantModule;
+import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.tenant.api.TenantInternalApi;
+import org.killbill.billing.tenant.api.TenantService;
+import org.killbill.billing.tenant.api.TenantUserApi;
+import org.killbill.billing.util.glue.KillBillModule;
+import org.mockito.Mockito;
+
+public class MockTenantModule extends KillBillModule implements TenantModule {
+
+    public MockTenantModule(final KillbillConfigSource configSource) {
+        super(configSource);
+    }
+
+    @Override
+    public void installTenantUserApi() {
+        bind(TenantUserApi.class).toInstance(Mockito.mock(TenantUserApi.class));
+        bind(TenantInternalApi.class).toInstance(Mockito.mock(TenantInternalApi.class));
+    }
+
+    @Override
+    public void installTenantService() {
+        bind(TenantService.class).toInstance(Mockito.mock(TenantService.class));
+    }
+
+    @Override
+    protected void configure() {
+        installTenantUserApi();
+        installTenantService();
+    }
+}
\ No newline at end of file