killbill-memoizeit

util: fix potential cross-tenants queries in InternalCallContextFactory Restrict

1/22/2015 1:46:29 PM

Changes

invoice/src/test/java/org/killbill/billing/invoice/notification/MockNextBillingDateNotifier.java 35(+0 -35)

invoice/src/test/java/org/killbill/billing/invoice/notification/MockNextBillingDatePoster.java 36(+0 -36)

Details

diff --git a/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java b/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
index 3840cd5..c0b2f2f 100644
--- a/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
+++ b/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -22,7 +24,6 @@ import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.entitlement.EntitlementTransitionType;
 import org.killbill.billing.events.AccountChangeInternalEvent;
@@ -46,12 +47,10 @@ import org.killbill.billing.events.UserTagDeletionInternalEvent;
 import org.killbill.billing.lifecycle.glue.BusModule;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallOrigin;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.bus.api.BusEvent;
 import org.killbill.bus.api.PersistentBus;
 import org.killbill.bus.api.PersistentBus.EventBusException;
@@ -70,23 +69,14 @@ public class BeatrixListener {
 
     private final PersistentBus externalBus;
     private final InternalCallContextFactory internalCallContextFactory;
-    private final AccountInternalApi accountApi;
-    private final NonEntityDao nonEntityDao;
-    private final CacheControllerDispatcher cacheControllerDispatcher;
 
     protected final ObjectMapper objectMapper;
 
     @Inject
     public BeatrixListener(@Named(BusModule.EXTERNAL_BUS_NAMED) final PersistentBus externalBus,
-                           final InternalCallContextFactory internalCallContextFactory,
-                           final AccountInternalApi accountApi,
-                           final  CacheControllerDispatcher cacheControllerDispatcher,
-                           final NonEntityDao nonEntityDao) {
+                           final InternalCallContextFactory internalCallContextFactory) {
         this.externalBus = externalBus;
         this.internalCallContextFactory = internalCallContextFactory;
-        this.accountApi = accountApi;
-        this.nonEntityDao = nonEntityDao;
-        this.cacheControllerDispatcher = cacheControllerDispatcher;
         this.objectMapper = new ObjectMapper();
         objectMapper.registerModule(new JodaModule());
         objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
@@ -243,19 +233,20 @@ public class BeatrixListener {
 
             default:
         }
-        final UUID accountId = getAccountIdFromRecordId(event.getBusEventType(), objectId, context.getAccountRecordId());
-        final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+
+        final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
+        final UUID accountId = getAccountId(event.getBusEventType(), objectId, objectType, tenantContext);
 
         return eventBusType != null ?
-               new DefaultBusExternalEvent(objectId, objectType, eventBusType, accountId, tenantId, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()) :
+               new DefaultBusExternalEvent(objectId, objectType, eventBusType, accountId, tenantContext.getTenantId(), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()) :
                null;
     }
 
-    private UUID getAccountIdFromRecordId(final BusInternalEventType eventType, final UUID objectId, final Long recordId) {
+    private UUID getAccountId(final BusInternalEventType eventType, final UUID objectId, final ObjectType objectType, final TenantContext context) {
         // accountRecord_id is not set for ACCOUNT_CREATE event as we are in the transaction and value is known yet
         if (eventType == BusInternalEventType.ACCOUNT_CREATE) {
             return objectId;
         }
-        return nonEntityDao.retrieveIdFromObject(recordId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+        return internalCallContextFactory.getAccountId(objectId, objectType, context);
     }
 }
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
index a96d33a..8da4329 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -27,9 +29,6 @@ import java.util.UUID;
 import javax.inject.Inject;
 
 import org.joda.time.DateTimeZone;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalCallContext;
@@ -41,15 +40,14 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.billing.util.customfield.ShouldntHappenException;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.SourcePaginationBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
@@ -85,31 +83,26 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
     private final EntitlementInternalApi entitlementInternalApi;
     private final SubscriptionBaseInternalApi subscriptionBaseInternalApi;
     private final InternalCallContextFactory internalCallContextFactory;
-    private final NonEntityDao nonEntityDao;
-    private final CacheControllerDispatcher cacheControllerDispatcher;
     private final EntitlementUtils entitlementUtils;
 
     @Inject
     public DefaultSubscriptionApi(final EntitlementInternalApi entitlementInternalApi, final SubscriptionBaseInternalApi subscriptionInternalApi,
-                                  final InternalCallContextFactory internalCallContextFactory, final EntitlementUtils entitlementUtils, final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
+                                  final InternalCallContextFactory internalCallContextFactory, final EntitlementUtils entitlementUtils) {
         this.entitlementInternalApi = entitlementInternalApi;
         this.subscriptionBaseInternalApi = subscriptionInternalApi;
         this.internalCallContextFactory = internalCallContextFactory;
-        this.nonEntityDao = nonEntityDao;
         this.entitlementUtils = entitlementUtils;
-        this.cacheControllerDispatcher = cacheControllerDispatcher;
     }
 
     @Override
     public Subscription getSubscriptionForEntitlementId(final UUID entitlementId, final TenantContext context) throws SubscriptionApiException {
-        final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(entitlementId, ObjectType.SUBSCRIPTION, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
-        final UUID accountId = nonEntityDao.retrieveIdFromObject(accountRecordId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+        final UUID accountId = internalCallContextFactory.getAccountId(entitlementId, ObjectType.SUBSCRIPTION, context);
 
         // Retrieve entitlements
         final AccountEntitlements accountEntitlements;
         try {
             accountEntitlements = entitlementInternalApi.getAllEntitlementsForAccountId(accountId, context);
-        } catch (EntitlementApiException e) {
+        } catch (final EntitlementApiException e) {
             throw new SubscriptionApiException(e);
         }
 
@@ -127,8 +120,7 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
 
     @Override
     public SubscriptionBundle getSubscriptionBundle(final UUID bundleId, final TenantContext context) throws SubscriptionApiException {
-        final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(bundleId, ObjectType.BUNDLE, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
-        final UUID accountId = nonEntityDao.retrieveIdFromObject(accountRecordId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+        final UUID accountId = internalCallContextFactory.getAccountId(bundleId, ObjectType.BUNDLE, context);
 
         final Optional<SubscriptionBundle> bundleOptional = Iterables.<SubscriptionBundle>tryFind(getSubscriptionBundlesForAccount(accountId, context),
                                                                                                   new Predicate<SubscriptionBundle>() {
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java b/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
index ca86524..389f75c 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -21,7 +21,6 @@ package org.killbill.billing.entitlement;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.entitlement.api.DefaultBlockingTransitionInternalEvent;
 import org.killbill.billing.entitlement.api.DefaultEntitlement;
@@ -34,12 +33,10 @@ import org.killbill.billing.entitlement.engine.core.EntitlementNotificationKey;
 import org.killbill.billing.entitlement.engine.core.EntitlementNotificationKeyAction;
 import org.killbill.billing.platform.api.LifecycleHandlerType;
 import org.killbill.billing.platform.api.LifecycleHandlerType.LifecycleLevel;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.CallOrigin;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.bus.api.BusEvent;
 import org.killbill.bus.api.PersistentBus;
 import org.killbill.bus.api.PersistentBus.EventBusException;
@@ -62,29 +59,23 @@ public class DefaultEntitlementService implements EntitlementService {
 
     private final EntitlementApi entitlementApi;
     private final BlockingStateDao blockingStateDao;
-    private final NonEntityDao nonEntityDao;
     private final PersistentBus eventBus;
     private final NotificationQueueService notificationQueueService;
     private final InternalCallContextFactory internalCallContextFactory;
-    private final CacheControllerDispatcher controllerDispatcher;
 
     private NotificationQueue entitlementEventQueue;
 
     @Inject
     public DefaultEntitlementService(final EntitlementApi entitlementApi,
                                      final BlockingStateDao blockingStateDao,
-                                     final NonEntityDao nonEntityDao,
                                      final PersistentBus eventBus,
                                      final NotificationQueueService notificationQueueService,
-                                     final InternalCallContextFactory internalCallContextFactory,
-                                     final CacheControllerDispatcher controllerDispatcher) {
+                                     final InternalCallContextFactory internalCallContextFactory) {
         this.entitlementApi = entitlementApi;
         this.blockingStateDao = blockingStateDao;
-        this.nonEntityDao = nonEntityDao;
         this.eventBus = eventBus;
         this.notificationQueueService = notificationQueueService;
         this.internalCallContextFactory = internalCallContextFactory;
-        this.controllerDispatcher = controllerDispatcher;
     }
 
     @Override
@@ -101,8 +92,8 @@ public class DefaultEntitlementService implements EntitlementService {
                     final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "EntitlementQueue", CallOrigin.INTERNAL, UserType.SYSTEM, fromNotificationQueueUserToken);
 
                     if (inputKey instanceof EntitlementNotificationKey) {
-                        final UUID tenantId = nonEntityDao.retrieveIdFromObject(tenantRecordId, ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
-                        processEntitlementNotification((EntitlementNotificationKey) inputKey, tenantId, internalCallContext);
+                        final CallContext callContext = internalCallContextFactory.createCallContext(internalCallContext);
+                        processEntitlementNotification((EntitlementNotificationKey) inputKey, internalCallContext, callContext);
                     } else if (inputKey instanceof BlockingTransitionNotificationKey) {
                         processBlockingNotification((BlockingTransitionNotificationKey) inputKey, internalCallContext);
                     } else if (inputKey != null) {
@@ -121,10 +112,10 @@ public class DefaultEntitlementService implements EntitlementService {
         }
     }
 
-    private void processEntitlementNotification(final EntitlementNotificationKey key, final UUID tenantId, final InternalCallContext internalCallContext) {
+    private void processEntitlementNotification(final EntitlementNotificationKey key, final InternalCallContext internalCallContext, final CallContext callContext) {
         final Entitlement entitlement;
         try {
-            entitlement = entitlementApi.getEntitlementForId(key.getEntitlementId(), internalCallContext.toTenantContext(tenantId));
+            entitlement = entitlementApi.getEntitlementForId(key.getEntitlementId(), callContext);
         } catch (final EntitlementApiException e) {
             log.error("Error retrieving entitlement for id " + key.getEntitlementId(), e);
             return;
@@ -139,11 +130,13 @@ public class DefaultEntitlementService implements EntitlementService {
         try {
             if (EntitlementNotificationKeyAction.CHANGE.equals(entitlementNotificationKeyAction) ||
                 EntitlementNotificationKeyAction.CANCEL.equals(entitlementNotificationKeyAction)) {
-                ((DefaultEntitlement) entitlement).blockAddOnsIfRequired(key.getEffectiveDate(), internalCallContext.toTenantContext(tenantId), internalCallContext);
-            } else if (EntitlementNotificationKeyAction.PAUSE.equals(entitlementNotificationKeyAction)) {
-                entitlementApi.pause(key.getBundleId(), key.getEffectiveDate().toLocalDate(), internalCallContext.toCallContext(tenantId));
-            } else if (EntitlementNotificationKeyAction.RESUME.equals(entitlementNotificationKeyAction)) {
-                entitlementApi.resume(key.getBundleId(), key.getEffectiveDate().toLocalDate(), internalCallContext.toCallContext(tenantId));
+                ((DefaultEntitlement) entitlement).blockAddOnsIfRequired(key.getEffectiveDate(), callContext, internalCallContext);
+            } else {
+                if (EntitlementNotificationKeyAction.PAUSE.equals(entitlementNotificationKeyAction)) {
+                    entitlementApi.pause(key.getBundleId(), key.getEffectiveDate().toLocalDate(), callContext);
+                } else if (EntitlementNotificationKeyAction.RESUME.equals(entitlementNotificationKeyAction)) {
+                    entitlementApi.resume(key.getBundleId(), key.getEffectiveDate().toLocalDate(), callContext);
+                }
             }
         } catch (final EntitlementApiException e) {
             log.error("Error processing event for entitlement {}" + entitlement.getId(), e);
@@ -164,7 +157,7 @@ public class DefaultEntitlementService implements EntitlementService {
 
         try {
             eventBus.post(event);
-        } catch (EventBusException e) {
+        } catch (final EventBusException e) {
             log.warn("Failed to post event {}", e);
         }
     }
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
index e97bda7..28e0e04 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -19,10 +21,6 @@ package org.killbill.billing.entitlement.block;
 import java.util.List;
 import java.util.UUID;
 
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.api.TestApiListener.NextEvent;
 import org.killbill.billing.callcontext.InternalCallContext;
@@ -30,8 +28,9 @@ import org.killbill.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
 import org.killbill.billing.entitlement.api.BlockingState;
 import org.killbill.billing.entitlement.api.BlockingStateType;
 import org.killbill.billing.junction.DefaultBlockingState;
-import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.util.callcontext.UserType;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
@@ -82,7 +81,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
         final boolean blockBilling = false;
 
         final Account account = accountApi.createAccount(getAccountData(7), callContext);
-        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), "TestBlockingApi", CallOrigin.TEST, UserType.SYSTEM, UUID.randomUUID());
+        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
 
         testListener.pushExpectedEvent(NextEvent.BLOCK);
         final BlockingState state1 = new DefaultBlockingState(uuid, BlockingStateType.ACCOUNT, overdueStateName, service, blockChange, blockEntitlement, blockBilling, clock.getUTCNow());
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index d128afd..cd2e38d 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -127,7 +129,6 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         });
     }
 
-
     @Override
     public List<InvoiceModelDao> getAllInvoicesByAccount(final InternalTenantContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
@@ -230,7 +231,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
                     cbaDao.addCBAComplexityFromTransaction(invoice, entitySqlDaoWrapperFactory, context);
 
-                    notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, invoice.getAccountId(), callbackDateTimePerSubscriptions, context.getUserToken());
+                    notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, invoice.getAccountId(), callbackDateTimePerSubscriptions, context);
                 }
                 return null;
             }
@@ -401,7 +402,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
                 // Retrieve invoice after the Refund
                 final InvoiceModelDao invoice = transInvoiceDao.getById(payment.getInvoiceId().toString(), context);
-                Preconditions.checkState(invoice !=  null, "Invoice shouldn't be null for payment " + payment.getId());
+                Preconditions.checkState(invoice != null, "Invoice shouldn't be null for payment " + payment.getId());
                 invoiceDaoHelper.populateChildren(invoice, entitySqlDaoWrapperFactory, context);
 
                 final BigDecimal invoiceBalanceAfterRefund = InvoiceModelDaoHelper.getBalance(invoice);
@@ -507,7 +508,6 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         });
     }
 
-
     @Override
     public BigDecimal getRemainingAmountPaid(final UUID invoicePaymentId, final InternalTenantContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<BigDecimal>() {
@@ -840,11 +840,11 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     }
 
     private void notifyOfFutureBillingEvents(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final UUID accountId,
-                                             final Map<UUID, List<DateTime>> callbackDateTimePerSubscriptions, final UUID userToken) {
+                                             final Map<UUID, List<DateTime>> callbackDateTimePerSubscriptions, final InternalCallContext internalCallContext) {
         for (final UUID subscriptionId : callbackDateTimePerSubscriptions.keySet()) {
             final List<DateTime> callbackDateTimeUTC = callbackDateTimePerSubscriptions.get(subscriptionId);
-            for (DateTime cur : callbackDateTimeUTC) {
-                nextBillingDatePoster.insertNextBillingNotificationFromTransaction(entitySqlDaoWrapperFactory, accountId, subscriptionId, cur, userToken);
+            for (final DateTime cur : callbackDateTimeUTC) {
+                nextBillingDatePoster.insertNextBillingNotificationFromTransaction(entitySqlDaoWrapperFactory, accountId, subscriptionId, cur, internalCallContext);
             }
         }
     }
@@ -854,7 +854,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         try {
             eventBus.postFromTransaction(new DefaultInvoiceAdjustmentEvent(invoiceId, accountId, context.getAccountRecordId(), context.getTenantRecordId(), userToken),
                                          entitySqlDaoWrapperFactory.getSqlDao());
-        } catch (EventBusException e) {
+        } catch (final EventBusException e) {
             log.warn("Failed to post adjustment event for invoice " + invoiceId, e);
         }
     }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
index ccd7440..9116ba0 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -28,7 +30,6 @@ import javax.annotation.Nullable;
 import org.joda.time.LocalDate;
 import org.joda.time.Months;
 import org.killbill.billing.ErrorCode;
-import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.BillingPeriod;
@@ -50,11 +51,10 @@ import org.killbill.billing.invoice.usage.SubscriptionConsumableInArrear;
 import org.killbill.billing.junction.BillingEvent;
 import org.killbill.billing.junction.BillingEventSet;
 import org.killbill.billing.usage.api.UsageUserApi;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.billing.util.config.InvoiceConfig;
 import org.killbill.billing.util.currency.KillBillMoney;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.clock.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -73,16 +73,14 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private final Clock clock;
     private final InvoiceConfig config;
     private final UsageUserApi usageApi;
-    private final NonEntityDao nonEntityDao;
-    private final CacheControllerDispatcher controllerDispatcher;
+    private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
-    public DefaultInvoiceGenerator(final Clock clock, final UsageUserApi usageApi, final InvoiceConfig config, final NonEntityDao nonEntityDao, final CacheControllerDispatcher controllerDispatcher) {
+    public DefaultInvoiceGenerator(final Clock clock, final UsageUserApi usageApi, final InvoiceConfig config, final InternalCallContextFactory internalCallContextFactory) {
         this.clock = clock;
         this.config = config;
         this.usageApi = usageApi;
-        this.nonEntityDao = nonEntityDao;
-        this.controllerDispatcher = controllerDispatcher;
+        this.internalCallContextFactory = internalCallContextFactory;
     }
 
     /*
@@ -116,8 +114,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private List<InvoiceItem> generateUsageInvoiceItems(final UUID invoiceId, final BillingEventSet eventSet,
                                                         @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
                                                         final InternalCallContext context) throws InvoiceApiException {
-
-        final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+        final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
         try {
 
             final List<InvoiceItem> items = Lists.newArrayList();
@@ -128,14 +125,14 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             while (events.hasNext()) {
                 final BillingEvent event = events.next();
                 // Skip events that are posterior to the targetDate
-                final LocalDate eventLocalEffectiveDate =  new LocalDate(event.getEffectiveDate(), event.getAccount().getTimeZone());
+                final LocalDate eventLocalEffectiveDate = new LocalDate(event.getEffectiveDate(), event.getAccount().getTimeZone());
                 if (eventLocalEffectiveDate.isAfter(targetDate)) {
                     continue;
                 }
 
                 final UUID subscriptionId = event.getSubscription().getId();
                 if (curSubscriptionId != null && !curSubscriptionId.equals(subscriptionId)) {
-                    final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(invoiceId, curEvents, usageApi, config.isInsertZeroUsageItems(), targetDate, context.toTenantContext(tenantId));
+                    final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(invoiceId, curEvents, usageApi, config.isInsertZeroUsageItems(), targetDate, tenantContext);
                     items.addAll(subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(extractUsageItemsForSubscription(curSubscriptionId, existingInvoices)));
                     curEvents = Lists.newArrayList();
                 }
@@ -143,7 +140,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
                 curEvents.add(event);
             }
             if (curSubscriptionId != null) {
-                final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(invoiceId, curEvents, usageApi, config.isInsertZeroUsageItems(), targetDate, context.toTenantContext(tenantId));
+                final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(invoiceId, curEvents, usageApi, config.isInsertZeroUsageItems(), targetDate, tenantContext);
                 items.addAll(subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(extractUsageItemsForSubscription(curSubscriptionId, existingInvoices)));
             }
             return items;
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 8debd89..4a0e1a9 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -33,18 +33,15 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
-import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
 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;
 import org.killbill.billing.events.BusInternalEvent;
 import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
 import org.killbill.billing.events.InvoiceAdjustmentInternalEvent;
@@ -73,11 +70,9 @@ import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.globallocker.LockerType;
 import org.killbill.billing.util.timezone.DateAndTimeZoneContext;
 import org.killbill.bus.api.PersistentBus;
@@ -106,37 +101,36 @@ public class InvoiceDispatcher {
     private final AccountInternalApi accountApi;
     private final SubscriptionBaseInternalApi subscriptionApi;
     private final InvoiceDao invoiceDao;
-    private final NonEntityDao nonEntityDao;
+    private final InternalCallContextFactory internalCallContextFactory;
     private final InvoiceNotifier invoiceNotifier;
     private final GlobalLocker locker;
     private final PersistentBus eventBus;
     private final Clock clock;
     private final OSGIServiceRegistration<InvoicePluginApi> pluginRegistry;
-    private final CacheControllerDispatcher controllerDispatcher;
 
     @Inject
     public InvoiceDispatcher(final OSGIServiceRegistration<InvoicePluginApi> pluginRegistry,
-                             final InvoiceGenerator generator, final AccountInternalApi accountApi,
+                             final InvoiceGenerator generator,
+                             final AccountInternalApi accountApi,
                              final BillingInternalApi billingApi,
                              final SubscriptionBaseInternalApi SubscriptionApi,
                              final InvoiceDao invoiceDao,
-                             final NonEntityDao nonEntityDao,
+                             final InternalCallContextFactory internalCallContextFactory,
                              final InvoiceNotifier invoiceNotifier,
                              final GlobalLocker locker,
                              final PersistentBus eventBus,
-                             final Clock clock, final CacheControllerDispatcher controllerDispatcher) {
+                             final Clock clock) {
         this.pluginRegistry = pluginRegistry;
         this.generator = generator;
         this.billingApi = billingApi;
         this.subscriptionApi = SubscriptionApi;
         this.accountApi = accountApi;
         this.invoiceDao = invoiceDao;
-        this.nonEntityDao = nonEntityDao;
+        this.internalCallContextFactory = internalCallContextFactory;
         this.invoiceNotifier = invoiceNotifier;
         this.locker = locker;
         this.eventBus = eventBus;
         this.clock = clock;
-        this.controllerDispatcher = controllerDispatcher;
     }
 
     public void processSubscription(final EffectiveSubscriptionInternalEvent transition,
@@ -337,11 +331,11 @@ public class InvoiceDispatcher {
     }
 
     private TenantContext buildTenantContext(final InternalTenantContext context) {
-        return context.toTenantContext(nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID)));
+        return internalCallContextFactory.createTenantContext(context);
     }
 
     private CallContext buildCallContext(final InternalCallContext context) {
-        return context.toCallContext(nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID)));
+        return internalCallContextFactory.createCallContext(context);
     }
 
     private List<InvoicePluginApi> getInvoicePlugins() {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
index 25e55c1..27db49b 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
@@ -19,22 +19,21 @@ package org.killbill.billing.invoice.notification;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
-import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.invoice.InvoiceListener;
 import org.killbill.billing.invoice.api.DefaultInvoiceService;
+import org.killbill.billing.subscription.api.SubscriptionBase;
+import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.config.InvoiceConfig;
 import org.killbill.notificationq.api.NotificationEvent;
 import org.killbill.notificationq.api.NotificationQueue;
 import org.killbill.notificationq.api.NotificationQueueService;
 import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
 import org.killbill.notificationq.api.NotificationQueueService.NotificationQueueAlreadyExists;
 import org.killbill.notificationq.api.NotificationQueueService.NotificationQueueHandler;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.config.InvoiceConfig;
-import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java
index 58c68ae..d4bd06e 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -20,19 +22,15 @@ import java.io.IOException;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.invoice.api.DefaultInvoiceService;
+import org.killbill.billing.util.entity.dao.EntitySqlDao;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 import org.killbill.notificationq.api.NotificationQueue;
 import org.killbill.notificationq.api.NotificationQueueService;
 import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
-import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 
@@ -41,20 +39,15 @@ public class DefaultNextBillingDatePoster implements NextBillingDatePoster {
     private static final Logger log = LoggerFactory.getLogger(DefaultNextBillingDatePoster.class);
 
     private final NotificationQueueService notificationQueueService;
-    private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
-    public DefaultNextBillingDatePoster(final NotificationQueueService notificationQueueService,
-                                        final InternalCallContextFactory internalCallContextFactory) {
+    public DefaultNextBillingDatePoster(final NotificationQueueService notificationQueueService) {
         this.notificationQueueService = notificationQueueService;
-        this.internalCallContextFactory = internalCallContextFactory;
     }
 
     @Override
     public void insertNextBillingNotificationFromTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final UUID accountId,
-                                                             final UUID subscriptionId, final DateTime futureNotificationTime, final UUID userToken) {
-        final InternalCallContext context = createCallContext(accountId, userToken);
-
+                                                             final UUID subscriptionId, final DateTime futureNotificationTime, final InternalCallContext internalCallContext) {
         final NotificationQueue nextBillingQueue;
         try {
             nextBillingQueue = notificationQueueService.getNotificationQueue(DefaultInvoiceService.INVOICE_SERVICE_NAME,
@@ -62,34 +55,12 @@ public class DefaultNextBillingDatePoster implements NextBillingDatePoster {
             log.info("Queuing next billing date notification at {} for subscriptionId {}", futureNotificationTime.toString(), subscriptionId.toString());
 
             nextBillingQueue.recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory.getSqlDao(), futureNotificationTime,
-                                                                     new NextBillingDateNotificationKey(subscriptionId), context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId());
-        } catch (NoSuchNotificationQueue e) {
+                                                                     new NextBillingDateNotificationKey(subscriptionId), internalCallContext.getUserToken(),
+                                                                     internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
+        } catch (final NoSuchNotificationQueue e) {
             log.error("Attempting to put items on a non-existent queue (NextBillingDateNotifier).", e);
-        } catch (IOException e) {
+        } catch (final IOException e) {
             log.error("Failed to serialize notificationKey for subscriptionId {}", subscriptionId);
         }
     }
-
-    @Override
-    public void insertNextBillingNotification(final UUID accountId, final UUID subscriptionId, final DateTime futureNotificationTime, final UUID userToken) {
-        final InternalCallContext context = createCallContext(accountId, userToken);
-
-        final NotificationQueue nextBillingQueue;
-        try {
-            nextBillingQueue = notificationQueueService.getNotificationQueue(DefaultInvoiceService.INVOICE_SERVICE_NAME,
-                                                                             DefaultNextBillingDateNotifier.NEXT_BILLING_DATE_NOTIFIER_QUEUE);
-            log.info("Queuing next billing date notification at {} for subscriptionId {}", futureNotificationTime.toString(), subscriptionId.toString());
-
-            nextBillingQueue.recordFutureNotification(futureNotificationTime,
-                                                      new NextBillingDateNotificationKey(subscriptionId), context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId());
-        } catch (NoSuchNotificationQueue e) {
-            log.error("Attempting to put items on a non-existent queue (NextBillingDateNotifier).", e);
-        } catch (IOException e) {
-            log.error("Failed to serialize notificationKey for subscriptionId {}", subscriptionId);
-        }
-    }
-
-    private InternalCallContext createCallContext(final UUID accountId, final UUID userToken) {
-        return internalCallContextFactory.createInternalCallContext(accountId, "NextBillingDatePoster", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
-    }
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDatePoster.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDatePoster.java
index 5a63e86..30f45ff 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDatePoster.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDatePoster.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -19,15 +21,12 @@ package org.killbill.billing.invoice.notification;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-
+import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
 import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 
 public interface NextBillingDatePoster {
 
     void insertNextBillingNotificationFromTransaction(EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, UUID accountId,
-                                                      UUID subscriptionId, DateTime futureNotificationTime, UUID userToken);
-
-    void insertNextBillingNotification(UUID accountId,
-                                       UUID subscriptionId, DateTime futureNotificationTime, UUID userToken);
+                                                      UUID subscriptionId, DateTime futureNotificationTime, InternalCallContext internalCallContext);
 }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
index 43bbfec..0343fbc 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -112,7 +114,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
                 return true;
             }
         };
-        this.generator = new DefaultInvoiceGenerator(clock, null, invoiceConfig, null, controllerDispatcher);
+        this.generator = new DefaultInvoiceGenerator(clock, null, invoiceConfig, internalCallContextFactory);
     }
 
     @Test(groups = "fast")
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 83c6bc6..1b2a4d0 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -39,7 +39,6 @@ import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
-import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.invoice.TestInvoiceHelper.DryRunFutureDateArguments;
 import org.killbill.billing.invoice.api.DryRunArguments;
 import org.killbill.billing.invoice.api.Invoice;
@@ -55,7 +54,6 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.util.timezone.DateAndTimeZoneContext;
 import org.killbill.clock.ClockMock;
-import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
@@ -90,14 +88,14 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
                                                       fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
                                                       BillingMode.IN_ADVANCE, "", 1L, SubscriptionBaseTransitionType.CREATE));
 
-        Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(),  Mockito.<InternalCallContext>any())).thenReturn(events);
+        Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
 
         final DateTime target = new DateTime();
 
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(pluginRegistry, generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   nonEntityDao, invoiceNotifier, locker, busService.getBus(),
-                                                                   clock, controllerDispatcher);
+                                                                   internalCallContextFactory, invoiceNotifier, locker, busService.getBus(),
+                                                                   clock);
 
         Invoice invoice = dispatcher.processAccount(accountId, target, new DryRunFutureDateArguments(), context);
         Assert.assertNotNull(invoice);
@@ -149,8 +147,8 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
         Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(pluginRegistry, generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   nonEntityDao, invoiceNotifier, locker, busService.getBus(),
-                                                                   clock, controllerDispatcher);
+                                                                   internalCallContextFactory, invoiceNotifier, locker, busService.getBus(),
+                                                                   clock);
 
         final Invoice invoice = dispatcher.processAccount(account.getId(), new DateTime("2012-07-30T00:00:00.000Z"), null, context);
         Assert.assertNotNull(invoice);
@@ -207,8 +205,8 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
 
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(pluginRegistry, generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   nonEntityDao, invoiceNotifier, locker, busService.getBus(),
-                                                                   clock, controllerDispatcher);
+                                                                   internalCallContextFactory, invoiceNotifier, locker, busService.getBus(),
+                                                                   clock);
 
         final Map<UUID, List<DateTime>> result = dispatcher.createNextFutureNotificationDate(Collections.singletonList(item), null, dateAndTimeZoneContext);
 
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index 407e59f..4fc02ca 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -74,11 +74,9 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.currency.KillBillMoney;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.clock.Clock;
 import org.killbill.commons.locker.GlobalLocker;
 import org.mockito.Mockito;
@@ -153,9 +151,7 @@ public class TestInvoiceHelper {
     private final GlobalLocker locker;
     private final Clock clock;
     private final InternalCallContext internalCallContext;
-    private final NonEntityDao nonEntityDao;
     private final InternalCallContextFactory internalCallContextFactory;
-    private final CacheControllerDispatcher cacheControllerDispatcher;
 
     // Low level SqlDao used by the tests to directly insert rows
     private final InvoicePaymentSqlDao invoicePaymentSqlDao;
@@ -164,8 +160,8 @@ public class TestInvoiceHelper {
     @Inject
     public TestInvoiceHelper(final OSGIServiceRegistration<InvoicePluginApi> pluginRegistry, final InvoiceGenerator generator, final IDBI dbi,
                              final BillingInternalApi billingApi, final AccountInternalApi accountApi, final AccountUserApi accountUserApi, final SubscriptionBaseInternalApi subscriptionApi, final BusService busService,
-                             final InvoiceDao invoiceDao, final GlobalLocker locker, final Clock clock, final NonEntityDao nonEntityDao, final InternalCallContext internalCallContext,
-                             final InternalCallContextFactory internalCallContextFactory, final CacheControllerDispatcher cacheControllerDispatcher) {
+                             final InvoiceDao invoiceDao, final GlobalLocker locker, final Clock clock, final InternalCallContext internalCallContext,
+                             final InternalCallContextFactory internalCallContextFactory) {
         this.pluginRegistry = pluginRegistry;
         this.generator = generator;
         this.billingApi = billingApi;
@@ -176,12 +172,10 @@ public class TestInvoiceHelper {
         this.invoiceDao = invoiceDao;
         this.locker = locker;
         this.clock = clock;
-        this.nonEntityDao = nonEntityDao;
         this.internalCallContext = internalCallContext;
         this.internalCallContextFactory = internalCallContextFactory;
         this.invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
         this.invoicePaymentSqlDao = dbi.onDemand(InvoicePaymentSqlDao.class);
-        this.cacheControllerDispatcher = cacheControllerDispatcher;
     }
 
     public UUID generateRegularInvoice(final Account account, final DateTime targetDate, final CallContext callContext) throws Exception {
@@ -202,8 +196,8 @@ public class TestInvoiceHelper {
 
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(pluginRegistry, generator, accountApi, billingApi, subscriptionApi,
-                                                                   invoiceDao, nonEntityDao, invoiceNotifier, locker, busService.getBus(),
-                                                                   clock, cacheControllerDispatcher);
+                                                                   invoiceDao, internalCallContextFactory, invoiceNotifier, locker, busService.getBus(),
+                                                                   clock);
 
         Invoice invoice = dispatcher.processAccount(account.getId(), targetDate, new DryRunFutureDateArguments(), internalCallContext);
         Assert.assertNotNull(invoice);
@@ -223,7 +217,7 @@ public class TestInvoiceHelper {
     }
 
     public SubscriptionBase createSubscription() throws SubscriptionBaseApiException {
-        UUID uuid = UUID.randomUUID();
+        final UUID uuid = UUID.randomUUID();
         final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
         Mockito.when(subscription.getId()).thenReturn(uuid);
         Mockito.when(subscriptionApi.getSubscriptionFromId(Mockito.<UUID>any(), Mockito.<InternalTenantContext>any())).thenReturn(subscription);
@@ -291,7 +285,7 @@ public class TestInvoiceHelper {
     public void createPayment(final InvoicePayment invoicePayment, final InternalCallContext internalCallContext) {
         try {
             invoicePaymentSqlDao.create(new InvoicePaymentModelDao(invoicePayment), internalCallContext);
-        } catch (EntityPersistenceException e) {
+        } catch (final EntityPersistenceException e) {
             Assert.fail(e.getMessage());
         }
     }
@@ -424,21 +418,27 @@ public class TestInvoiceHelper {
             }
         };
     }
+
     public static class DryRunFutureDateArguments implements DryRunArguments {
+
         public DryRunFutureDateArguments() {
         }
+
         @Override
         public PlanPhaseSpecifier getPlanPhaseSpecifier() {
             return null;
         }
+
         @Override
         public SubscriptionEventType getAction() {
             return null;
         }
+
         @Override
         public UUID getSubscriptionId() {
             return null;
         }
+
         @Override
         public DateTime getEffectiveDate() {
             return null;
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
index 7a5735a..d59430a 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -57,9 +59,8 @@ import org.killbill.billing.overdue.notification.OverdueCheckNotifier;
 import org.killbill.billing.overdue.notification.OverduePoster;
 import org.killbill.billing.tag.TagInternalApi;
 import org.killbill.billing.util.api.TagApiException;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
-import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.email.DefaultEmailSender;
 import org.killbill.billing.util.email.EmailApiException;
 import org.killbill.billing.util.email.EmailConfig;
@@ -90,8 +91,7 @@ public class OverdueStateApplicator {
     private final OverdueEmailGenerator overdueEmailGenerator;
     private final TagInternalApi tagApi;
     private final EmailSender emailSender;
-    private final NonEntityDao nonEntityDao;
-    private final CacheControllerDispatcher controllerDispatcher;
+    private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
     public OverdueStateApplicator(final BlockingInternalApi accessApi,
@@ -102,9 +102,8 @@ public class OverdueStateApplicator {
                                   final OverdueEmailGenerator overdueEmailGenerator,
                                   final EmailConfig config,
                                   final PersistentBus bus,
-                                  final NonEntityDao nonEntityDao,
                                   final TagInternalApi tagApi,
-                                  final CacheControllerDispatcher controllerDispatcher) {
+                                  final InternalCallContextFactory internalCallContextFactory) {
 
         this.blockingApi = accessApi;
         this.accountApi = accountApi;
@@ -113,10 +112,9 @@ public class OverdueStateApplicator {
         this.checkPoster = checkPoster;
         this.overdueEmailGenerator = overdueEmailGenerator;
         this.tagApi = tagApi;
-        this.nonEntityDao = nonEntityDao;
+        this.internalCallContextFactory = internalCallContextFactory;
         this.emailSender = new DefaultEmailSender(config);
         this.bus = bus;
-        this.controllerDispatcher = controllerDispatcher;
     }
 
     public void apply(final OverdueStateSet overdueStateSet, final BillingState billingState,
@@ -165,7 +163,7 @@ public class OverdueStateApplicator {
             // on the bus to which invoice will react. We need the latest state (including AUTO_INVOICE_OFF tag for example)
             // to be present in the database first.
             storeNewState(account, nextOverdueState, context);
-        } catch (OverdueApiException e) {
+        } catch (final OverdueApiException e) {
             if (e.getCode() != ErrorCode.OVERDUE_NO_REEVALUATION_INTERVAL.getCode()) {
                 throw new OverdueException(e);
             }
@@ -173,7 +171,7 @@ public class OverdueStateApplicator {
         try {
             bus.post(createOverdueEvent(account, previousOverdueState.getName(), nextOverdueState.getName(), isBlockBillingTransition(previousOverdueState, nextOverdueState),
                                         isUnblockBillingTransition(previousOverdueState, nextOverdueState), context));
-        } catch (Exception e) {
+        } catch (final Exception e) {
             log.error("Error posting overdue change event to bus", e);
         }
     }
@@ -197,14 +195,14 @@ public class OverdueStateApplicator {
 
         try {
             avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(account, previousOverdueState, clearState, context);
-        } catch (OverdueApiException e) {
+        } catch (final OverdueApiException e) {
             throw new OverdueException(e);
         }
 
         try {
             bus.post(createOverdueEvent(account, previousOverdueState.getName(), clearState.getName(), isBlockBillingTransition(previousOverdueState, clearState),
                                         isUnblockBillingTransition(previousOverdueState, clearState), context));
-        } catch (Exception e) {
+        } catch (final Exception e) {
             log.error("Error posting overdue change event to bus", e);
         }
     }
@@ -226,7 +224,7 @@ public class OverdueStateApplicator {
                                                                   blockBilling(nextOverdueState),
                                                                   clock.getUTCNow()),
                                          context);
-        } catch (Exception e) {
+        } catch (final Exception e) {
             throw new OverdueException(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, blockable.getId(), blockable.getClass().getName());
         }
     }
@@ -234,7 +232,7 @@ public class OverdueStateApplicator {
     private void set_AUTO_INVOICE_OFF_on_blockedBilling(final UUID accountId, final InternalCallContext context) throws OverdueApiException {
         try {
             tagApi.addTag(accountId, ObjectType.ACCOUNT, ControlTagType.AUTO_INVOICING_OFF.getId(), context);
-        } catch (TagApiException e) {
+        } catch (final TagApiException e) {
             throw new OverdueApiException(e);
         }
     }
@@ -242,7 +240,7 @@ public class OverdueStateApplicator {
     private void remove_AUTO_INVOICE_OFF_on_clear(final UUID accountId, final InternalCallContext context) throws OverdueApiException {
         try {
             tagApi.removeTag(accountId, ObjectType.ACCOUNT, ControlTagType.AUTO_INVOICING_OFF.getId(), context);
-        } catch (TagApiException e) {
+        } catch (final TagApiException e) {
             if (e.getCode() != ErrorCode.TAG_DOES_NOT_EXIST.getCode()) {
                 throw new OverdueApiException(e);
             }
@@ -283,6 +281,8 @@ public class OverdueStateApplicator {
         if (nextOverdueState.getOverdueCancellationPolicy() == OverdueCancellationPolicy.NONE) {
             return;
         }
+
+        final CallContext callContext = internalCallContextFactory.createCallContext(context);
         try {
             final BillingActionPolicy actionPolicy;
             switch (nextOverdueState.getOverdueCancellationPolicy()) {
@@ -296,27 +296,25 @@ public class OverdueStateApplicator {
                     throw new IllegalStateException("Unexpected OverdueCancellationPolicy " + nextOverdueState.getOverdueCancellationPolicy());
             }
             final List<Entitlement> toBeCancelled = new LinkedList<Entitlement>();
-            computeEntitlementsToCancel(account, toBeCancelled, context);
+            computeEntitlementsToCancel(account, toBeCancelled, callContext);
 
-            final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
             for (final Entitlement cur : toBeCancelled) {
                 try {
-                    cur.cancelEntitlementWithDateOverrideBillingPolicy(new LocalDate(clock.getUTCNow(), account.getTimeZone()), actionPolicy, context.toCallContext(tenantId));
-                } catch (EntitlementApiException e) {
+                    cur.cancelEntitlementWithDateOverrideBillingPolicy(new LocalDate(clock.getUTCNow(), account.getTimeZone()), actionPolicy, callContext);
+                } catch (final EntitlementApiException e) {
                     // If subscription has already been cancelled, there is nothing to do so we can ignore
                     if (e.getCode() != ErrorCode.SUB_CANCEL_BAD_STATE.getCode()) {
                         throw new OverdueException(e);
                     }
                 }
             }
-        } catch (EntitlementApiException e) {
+        } catch (final EntitlementApiException e) {
             throw new OverdueException(e);
         }
     }
 
-    private void computeEntitlementsToCancel(final Account account, final List<Entitlement> result, final InternalTenantContext context) throws EntitlementApiException {
-        final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
-        final List<Entitlement> allEntitlementsForAccountId = entitlementApi.getAllEntitlementsForAccountId(account.getId(), context.toTenantContext(tenantId));
+    private void computeEntitlementsToCancel(final Account account, final List<Entitlement> result, final CallContext context) throws EntitlementApiException {
+        final List<Entitlement> allEntitlementsForAccountId = entitlementApi.getAllEntitlementsForAccountId(account.getId(), context);
         // Entitlement is smart enough and will cancel the associated add-ons. See also discussion in https://github.com/killbill/killbill/issues/94
         final Collection<Entitlement> allEntitlementsButAddonsForAccountId = Collections2.<Entitlement>filter(allEntitlementsForAccountId,
                                                                                                               new Predicate<Entitlement>() {
@@ -352,11 +350,11 @@ public class OverdueStateApplicator {
             } else {
                 emailSender.sendPlainTextEmail(to, cc, subject, emailBody);
             }
-        } catch (IOException e) {
+        } catch (final IOException e) {
             log.warn(String.format("Unable to generate or send overdue notification email for account %s and overdueable %s", account.getId(), account.getId()), e);
-        } catch (EmailApiException e) {
+        } catch (final EmailApiException e) {
             log.warn(String.format("Unable to send overdue notification email for account %s and overdueable %s", account.getId(), account.getId()), e);
-        } catch (MustacheException e) {
+        } catch (final MustacheException e) {
             log.warn(String.format("Unable to generate overdue notification email for account %s and overdueable %s", account.getId(), account.getId()), e);
         }
     }
@@ -370,13 +368,13 @@ public class OverdueStateApplicator {
             final UUID accountId = accountApi.getByRecordId(context.getAccountRecordId(), context);
 
             final List<Tag> accountTags = tagApi.getTags(accountId, ObjectType.ACCOUNT, context);
-            for (Tag cur : accountTags) {
+            for (final Tag cur : accountTags) {
                 if (cur.getTagDefinitionId().equals(ControlTagType.OVERDUE_ENFORCEMENT_OFF.getId())) {
                     return true;
                 }
             }
             return false;
-        } catch (AccountApiException e) {
+        } catch (final AccountApiException e) {
             throw new OverdueException(e);
         }
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/bus/InvoiceHandler.java b/payment/src/main/java/org/killbill/billing/payment/bus/InvoiceHandler.java
index 80c1770..22dd22c 100644
--- a/payment/src/main/java/org/killbill/billing/payment/bus/InvoiceHandler.java
+++ b/payment/src/main/java/org/killbill/billing/payment/bus/InvoiceHandler.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -25,7 +25,6 @@ import java.util.List;
 import java.util.UUID;
 
 import org.killbill.billing.ErrorCode;
-import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
@@ -35,14 +34,11 @@ import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.core.PluginRoutingPaymentProcessor;
 import org.killbill.billing.payment.invoice.InvoicePaymentRoutingPluginApi;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.CallOrigin;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.UserType;
 import org.killbill.billing.util.config.PaymentConfig;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,8 +50,6 @@ public class InvoiceHandler {
     private final AccountInternalApi accountApi;
     private final InternalCallContextFactory internalCallContextFactory;
     private final PluginRoutingPaymentProcessor pluginRoutingPaymentProcessor;
-    private final NonEntityDao nonEntityDao;
-    private final CacheControllerDispatcher controllerDispatcher;
     private final PaymentConfig paymentConfig;
 
     private static final Logger log = LoggerFactory.getLogger(InvoiceHandler.class);
@@ -64,20 +58,15 @@ public class InvoiceHandler {
     public InvoiceHandler(final PaymentConfig paymentConfig,
                           final AccountInternalApi accountApi,
                           final PluginRoutingPaymentProcessor pluginRoutingPaymentProcessor,
-                          final NonEntityDao nonEntityDao,
-                          final InternalCallContextFactory internalCallContextFactory,
-                          final CacheControllerDispatcher controllerDispatcher) {
+                          final InternalCallContextFactory internalCallContextFactory) {
         this.paymentConfig = paymentConfig;
         this.accountApi = accountApi;
         this.internalCallContextFactory = internalCallContextFactory;
         this.pluginRoutingPaymentProcessor = pluginRoutingPaymentProcessor;
-        this.nonEntityDao = nonEntityDao;
-        this.controllerDispatcher = controllerDispatcher;
     }
 
     @Subscribe
     public void processInvoiceEvent(final InvoiceCreationInternalEvent event) {
-
         log.info("Received invoice creation notification for account {} and invoice {}",
                  event.getAccountId(), event.getInvoiceId());
 
@@ -90,7 +79,7 @@ public class InvoiceHandler {
             final PluginProperty prop1 = new PluginProperty(InvoicePaymentRoutingPluginApi.PROP_IPCD_INVOICE_ID, event.getInvoiceId().toString(), false);
             properties.add(prop1);
 
-            final CallContext callContext = internalContext.toCallContext(nonEntityDao.retrieveIdFromObject(internalContext.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID)));
+            final CallContext callContext = internalCallContextFactory.createCallContext(internalContext);
 
             final BigDecimal amountToBePaid = null; // We let the plugin compute how much should be paid
             final List<String> paymentControlPluginNames = paymentConfig.getPaymentControlPluginNames() != null ? new LinkedList<String>(paymentConfig.getPaymentControlPluginNames()) : new LinkedList<String>();
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/AttemptCompletionTask.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/AttemptCompletionTask.java
index fcf5796..95fe5bc 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/AttemptCompletionTask.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/AttemptCompletionTask.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -19,7 +19,6 @@ package org.killbill.billing.payment.core.janitor;
 
 import java.util.List;
 
-import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
@@ -38,11 +37,9 @@ import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
 import org.killbill.billing.payment.dao.PluginPropertySerializer;
 import org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.config.PaymentConfig;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.clock.Clock;
 
 import com.google.common.base.Predicate;
@@ -57,10 +54,10 @@ import com.google.common.collect.Iterables;
 final class AttemptCompletionTask extends CompletionTaskBase<PaymentAttemptModelDao> {
 
     public AttemptCompletionTask(final Janitor janitor, final InternalCallContextFactory internalCallContextFactory, final PaymentConfig paymentConfig,
-                                 final NonEntityDao nonEntityDao, final PaymentDao paymentDao, final Clock clock, final PaymentStateMachineHelper paymentStateMachineHelper,
-                                 final RetryStateMachineHelper retrySMHelper, final CacheControllerDispatcher controllerDispatcher, final AccountInternalApi accountInternalApi,
+                                 final PaymentDao paymentDao, final Clock clock, final PaymentStateMachineHelper paymentStateMachineHelper,
+                                 final RetryStateMachineHelper retrySMHelper, final AccountInternalApi accountInternalApi,
                                  final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry) {
-        super(janitor, internalCallContextFactory, paymentConfig, nonEntityDao, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, controllerDispatcher, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
+        super(janitor, internalCallContextFactory, paymentConfig, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
     }
 
     @Override
@@ -72,7 +69,7 @@ final class AttemptCompletionTask extends CompletionTaskBase<PaymentAttemptModel
 
     @Override
     public void doIteration(final PaymentAttemptModelDao attempt) {
-        final InternalTenantContext tenantContext = internalCallContextFactory.createInternalTenantContext(attempt.getAccountId(), attempt.getId(), ObjectType.PAYMENT_ATTEMPT);
+        final InternalTenantContext tenantContext = internalCallContextFactory.createInternalTenantContext(attempt.getTenantRecordId(), attempt.getAccountRecordId());
         final CallContext callContext = createCallContext("AttemptCompletionJanitorTask", tenantContext);
         final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(attempt.getAccountId(), callContext);
 
@@ -117,11 +114,11 @@ final class AttemptCompletionTask extends CompletionTaskBase<PaymentAttemptModel
             // to the PaymentControlPluginApi plugin and transition the state.
             //
             pluginControlledPaymentAutomatonRunner.completeRun(paymentStateContext);
-        } catch (AccountApiException e) {
+        } catch (final AccountApiException e) {
             log.warn("Janitor AttemptCompletionTask failed to complete payment attempt " + attempt.getId(), e);
-        } catch (PluginPropertySerializerException e) {
+        } catch (final PluginPropertySerializerException e) {
             log.warn("Janitor AttemptCompletionTask failed to complete payment attempt " + attempt.getId(), e);
-        } catch (PaymentApiException e) {
+        } catch (final PaymentApiException e) {
             log.warn("Janitor AttemptCompletionTask failed to complete payment attempt " + attempt.getId(), e);
         }
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
index ef84a79..623ab72 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -21,7 +21,6 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.DefaultCallContext;
 import org.killbill.billing.callcontext.InternalCallContext;
@@ -32,14 +31,12 @@ import org.killbill.billing.payment.core.sm.PluginRoutingPaymentAutomatonRunner;
 import org.killbill.billing.payment.core.sm.RetryStateMachineHelper;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.CallOrigin;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.billing.util.callcontext.UserType;
 import org.killbill.billing.util.config.PaymentConfig;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.clock.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,7 +45,7 @@ abstract class CompletionTaskBase<T> implements Runnable {
 
     protected Logger log = LoggerFactory.getLogger(CompletionTaskBase.class);
 
-    private Janitor janitor;
+    private final Janitor janitor;
     private final String taskName;
 
     protected final PaymentConfig paymentConfig;
@@ -56,28 +53,23 @@ abstract class CompletionTaskBase<T> implements Runnable {
     protected final PaymentDao paymentDao;
     protected final InternalCallContext completionTaskCallContext;
     protected final InternalCallContextFactory internalCallContextFactory;
-    protected final NonEntityDao nonEntityDao;
     protected final PaymentStateMachineHelper paymentStateMachineHelper;
     protected final RetryStateMachineHelper retrySMHelper;
-    protected final CacheControllerDispatcher controllerDispatcher;
     protected final AccountInternalApi accountInternalApi;
     protected final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner;
     protected final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry;
 
-
     public CompletionTaskBase(final Janitor janitor, final InternalCallContextFactory internalCallContextFactory, final PaymentConfig paymentConfig,
-                              final NonEntityDao nonEntityDao, final PaymentDao paymentDao, final Clock clock, final PaymentStateMachineHelper paymentStateMachineHelper,
-                              final RetryStateMachineHelper retrySMHelper, final CacheControllerDispatcher controllerDispatcher, final AccountInternalApi accountInternalApi,
+                              final PaymentDao paymentDao, final Clock clock, final PaymentStateMachineHelper paymentStateMachineHelper,
+                              final RetryStateMachineHelper retrySMHelper, final AccountInternalApi accountInternalApi,
                               final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry) {
         this.janitor = janitor;
         this.internalCallContextFactory = internalCallContextFactory;
         this.paymentConfig = paymentConfig;
-        this.nonEntityDao = nonEntityDao;
         this.paymentDao = paymentDao;
         this.clock = clock;
         this.paymentStateMachineHelper = paymentStateMachineHelper;
         this.retrySMHelper = retrySMHelper;
-        this.controllerDispatcher = controllerDispatcher;
         this.accountInternalApi = accountInternalApi;
         this.pluginControlledPaymentAutomatonRunner = pluginControlledPaymentAutomatonRunner;
         this.pluginRegistry = pluginRegistry;
@@ -94,14 +86,14 @@ abstract class CompletionTaskBase<T> implements Runnable {
             return;
         }
         final List<T> items = getItemsForIteration();
-        for (T item : items) {
+        for (final T item : items) {
             if (janitor.isStopped()) {
                 log.info("Janitor Task " + taskName + " was requested to stop");
                 return;
             }
             try {
                 doIteration(item);
-            } catch(IllegalStateException e) {
+            } catch (final IllegalStateException e) {
                 log.warn(e.getMessage());
             }
         }
@@ -111,13 +103,12 @@ abstract class CompletionTaskBase<T> implements Runnable {
 
     public abstract void doIteration(final T item);
 
-    protected CallContext createCallContext(final String taskName, final InternalTenantContext tenantContext) {
-        final UUID tenantId = nonEntityDao.retrieveIdFromObject(tenantContext.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
-        final CallContext callContext = new DefaultCallContext(tenantId, taskName, CallOrigin.INTERNAL, UserType.SYSTEM, UUID.randomUUID(), clock);
+    protected CallContext createCallContext(final String taskName, final InternalTenantContext internalTenantContext) {
+        final TenantContext tenantContext = internalCallContextFactory.createTenantContext(internalTenantContext);
+        final CallContext callContext = new DefaultCallContext(tenantContext.getTenantId(), taskName, CallOrigin.INTERNAL, UserType.SYSTEM, UUID.randomUUID(), clock);
         return callContext;
     }
 
-
     protected DateTime getCreatedDateBefore() {
         final long delayBeforeNowMs = paymentConfig.getJanitorPendingCleanupTime().getMillis();
         return clock.getUTCNow().minusMillis((int) delayBeforeNowMs);
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/ErroredPaymentTask.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/ErroredPaymentTask.java
index 44c098b..922e369 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/ErroredPaymentTask.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/ErroredPaymentTask.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -23,7 +23,6 @@ import java.util.List;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
@@ -42,11 +41,9 @@ import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApiException;
 import org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.config.PaymentConfig;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.clock.Clock;
 
 import com.google.common.base.Preconditions;
@@ -62,16 +59,16 @@ public class ErroredPaymentTask extends CompletionTaskBase<PaymentModelDao> {
     private final int MAX_ITEMS_PER_LOOP = 100; // Limit of items per iteration
 
     public ErroredPaymentTask(final Janitor janitor, final InternalCallContextFactory internalCallContextFactory, final PaymentConfig paymentConfig,
-                                 final NonEntityDao nonEntityDao, final PaymentDao paymentDao, final Clock clock,
-                                 final PaymentStateMachineHelper paymentStateMachineHelper, final RetryStateMachineHelper retrySMHelper, final CacheControllerDispatcher controllerDispatcher, final AccountInternalApi accountInternalApi,
-                                 final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry) {
-        super(janitor, internalCallContextFactory, paymentConfig, nonEntityDao, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, controllerDispatcher, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
+                              final PaymentDao paymentDao, final Clock clock,
+                              final PaymentStateMachineHelper paymentStateMachineHelper, final RetryStateMachineHelper retrySMHelper, final AccountInternalApi accountInternalApi,
+                              final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry) {
+        super(janitor, internalCallContextFactory, paymentConfig, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
     }
 
     @Override
     public List<PaymentModelDao> getItemsForIteration() {
         // In theory this should be the plugin timeout but we add a 3 minutes delay for safety.
-        int delayBeforeNow = (int) paymentConfig.getPaymentPluginTimeout().getMillis() + SAFETY_DELAY_MS;
+        final int delayBeforeNow = (int) paymentConfig.getPaymentPluginTimeout().getMillis() + SAFETY_DELAY_MS;
         final DateTime createdBeforeDate = clock.getUTCNow().minusMillis(delayBeforeNow);
 
         // We want to avoid iterating on the same failed payments -- if for some reasons they can't fix themselves.
@@ -84,13 +81,12 @@ public class ErroredPaymentTask extends CompletionTaskBase<PaymentModelDao> {
 
     @Override
     public void doIteration(final PaymentModelDao item) {
-
-        final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(item.getAccountId(), item.getId(), ObjectType.PAYMENT);
+        final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(item.getTenantRecordId(), item.getAccountRecordId());
         final CallContext callContext = createCallContext("ErroredPaymentTask", internalTenantContext);
         final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(item.getAccountId(), callContext);
 
         final List<PaymentTransactionModelDao> transactions = paymentDao.getTransactionsForPayment(item.getId(), internalTenantContext);
-        Preconditions.checkState(! transactions.isEmpty(), "Janitor ErroredPaymentTask found item " + item.getId() + " with no transactions, skipping");
+        Preconditions.checkState(!transactions.isEmpty(), "Janitor ErroredPaymentTask found item " + item.getId() + " with no transactions, skipping");
 
         // We look for latest transaction in an UNKNOWN state, if not we skip
         final PaymentTransactionModelDao unknownTransaction = transactions.get(transactions.size() - 1);
@@ -101,7 +97,6 @@ public class ErroredPaymentTask extends CompletionTaskBase<PaymentModelDao> {
         final PaymentMethodModelDao paymentMethod = paymentDao.getPaymentMethod(item.getPaymentMethodId(), internalCallContext);
         final PaymentPluginApi paymentPluginApi = getPaymentPluginApi(item, paymentMethod.getPluginName());
 
-
         PaymentTransactionInfoPlugin pluginErroredTransaction = null;
         try {
             final List<PaymentTransactionInfoPlugin> result = paymentPluginApi.getPaymentInfo(item.getAccountId(), item.getId(), ImmutableList.<PluginProperty>of(), callContext);
@@ -112,7 +107,7 @@ public class ErroredPaymentTask extends CompletionTaskBase<PaymentModelDao> {
                     return input.getKbTransactionPaymentId().equals(unknownTransaction.getId());
                 }
             }).orNull();
-        } catch (PaymentPluginApiException ignored) {
+        } catch (final PaymentPluginApiException ignored) {
 
         }
 
@@ -143,8 +138,7 @@ public class ErroredPaymentTask extends CompletionTaskBase<PaymentModelDao> {
         }
         final String lastSuccessPaymentState = paymentStateMachineHelper.isSuccessState(newPaymentState) ? newPaymentState : null;
 
-
-        final BigDecimal processedAmount = pluginErroredTransaction != null ?  pluginErroredTransaction.getAmount() : null;
+        final BigDecimal processedAmount = pluginErroredTransaction != null ? pluginErroredTransaction.getAmount() : null;
         final Currency processedCurrency = pluginErroredTransaction != null ? pluginErroredTransaction.getCurrency() : null;
         final String gatewayErrorCode = pluginErroredTransaction != null ? pluginErroredTransaction.getGatewayErrorCode() : null;
         final String gatewayError = pluginErroredTransaction != null ? pluginErroredTransaction.getGatewayError() : null;
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/Janitor.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/Janitor.java
index a87d870..cd39edc 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/Janitor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/Janitor.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -31,10 +31,8 @@ import org.killbill.billing.payment.core.sm.RetryStateMachineHelper;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.glue.PaymentModule;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.config.PaymentConfig;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.clock.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,9 +42,9 @@ import org.slf4j.LoggerFactory;
  */
 public class Janitor {
 
-    private final static Logger log = LoggerFactory.getLogger(Janitor.class);
+    private static final Logger log = LoggerFactory.getLogger(Janitor.class);
 
-    private final static int TERMINATION_TIMEOUT_SEC = 5;
+    private static final int TERMINATION_TIMEOUT_SEC = 5;
 
     private final ScheduledExecutorService janitorExecutor;
     private final PaymentConfig paymentConfig;
@@ -61,22 +59,20 @@ public class Janitor {
                    final PaymentDao paymentDao,
                    final PaymentConfig paymentConfig,
                    final Clock clock,
-                   final NonEntityDao nonEntityDao,
                    final InternalCallContextFactory internalCallContextFactory,
                    final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner,
                    @Named(PaymentModule.JANITOR_EXECUTOR_NAMED) final ScheduledExecutorService janitorExecutor,
                    final PaymentStateMachineHelper paymentSMHelper,
                    final RetryStateMachineHelper retrySMHelper,
-                   final CacheControllerDispatcher controllerDispatcher,
                    final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry) {
         this.janitorExecutor = janitorExecutor;
         this.paymentConfig = paymentConfig;
-        this.pendingTransactionTask = new PendingTransactionTask(this, internalCallContextFactory, paymentConfig, nonEntityDao, paymentDao, clock, paymentSMHelper, retrySMHelper,
-                                                                 controllerDispatcher, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
-        this.attemptCompletionTask = new AttemptCompletionTask(this, internalCallContextFactory, paymentConfig, nonEntityDao, paymentDao, clock, paymentSMHelper, retrySMHelper,
-                                                               controllerDispatcher, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
-        this.erroredPaymentCompletionTask = new ErroredPaymentTask(this, internalCallContextFactory, paymentConfig, nonEntityDao, paymentDao, clock, paymentSMHelper, retrySMHelper,
-                                                               controllerDispatcher, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
+        this.pendingTransactionTask = new PendingTransactionTask(this, internalCallContextFactory, paymentConfig, paymentDao, clock, paymentSMHelper, retrySMHelper,
+                                                                 accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
+        this.attemptCompletionTask = new AttemptCompletionTask(this, internalCallContextFactory, paymentConfig, paymentDao, clock, paymentSMHelper, retrySMHelper,
+                                                               accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
+        this.erroredPaymentCompletionTask = new ErroredPaymentTask(this, internalCallContextFactory, paymentConfig, paymentDao, clock, paymentSMHelper, retrySMHelper,
+                                                                   accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
         this.isStopped = false;
     }
 
@@ -114,11 +110,11 @@ public class Janitor {
              * Then, awaitTermination with a timeout is required to ensure tasks completed.
              */
             janitorExecutor.shutdown();
-            boolean success = janitorExecutor.awaitTermination(TERMINATION_TIMEOUT_SEC, TimeUnit.SECONDS);
+            final boolean success = janitorExecutor.awaitTermination(TERMINATION_TIMEOUT_SEC, TimeUnit.SECONDS);
             if (!success) {
                 log.warn("Janitor failed to complete termination within " + TERMINATION_TIMEOUT_SEC + "sec");
             }
-        } catch (InterruptedException e) {
+        } catch (final InterruptedException e) {
             Thread.currentThread().interrupt();
             log.warn("Janitor stop sequence got interrupted");
         } finally {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/PendingTransactionTask.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/PendingTransactionTask.java
index d5f40d0..97c65a4 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/PendingTransactionTask.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/PendingTransactionTask.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -27,10 +27,8 @@ import org.killbill.billing.payment.core.sm.PluginRoutingPaymentAutomatonRunner;
 import org.killbill.billing.payment.core.sm.RetryStateMachineHelper;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.config.PaymentConfig;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.clock.Clock;
 
 import com.google.common.collect.ImmutableList;
@@ -40,14 +38,13 @@ import com.google.common.collect.ImmutableList;
  */
 final class PendingTransactionTask extends CompletionTaskBase<Integer> {
 
-    private Janitor janitor;
     private final List<Integer> itemsForIterations;
 
     public PendingTransactionTask(final Janitor janitor, final InternalCallContextFactory internalCallContextFactory, final PaymentConfig paymentConfig,
-                                 final NonEntityDao nonEntityDao, final PaymentDao paymentDao, final Clock clock, final PaymentStateMachineHelper paymentStateMachineHelper,
-                                 final RetryStateMachineHelper retrySMHelper, final CacheControllerDispatcher controllerDispatcher, final AccountInternalApi accountInternalApi,
-                                 final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry) {
-        super(janitor, internalCallContextFactory, paymentConfig, nonEntityDao, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, controllerDispatcher, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
+                                  final PaymentDao paymentDao, final Clock clock, final PaymentStateMachineHelper paymentStateMachineHelper,
+                                  final RetryStateMachineHelper retrySMHelper, final AccountInternalApi accountInternalApi,
+                                  final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry) {
+        super(janitor, internalCallContextFactory, paymentConfig, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, accountInternalApi, pluginControlledPaymentAutomatonRunner, pluginRegistry);
         this.itemsForIterations = ImmutableList.of(new Integer(1));
     }
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
index e01c8ab..4a3d16f 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -39,10 +39,9 @@ import org.killbill.billing.payment.plugin.api.HostedPaymentPageFormDescriptor;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApiException;
 import org.killbill.billing.tag.TagInternalApi;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.config.PaymentConfig;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.clock.Clock;
 import org.killbill.commons.locker.GlobalLocker;
 import org.slf4j.Logger;
@@ -71,13 +70,12 @@ public class PaymentGatewayProcessor extends ProcessorBase {
                                    final InvoiceInternalApi invoiceApi,
                                    final TagInternalApi tagUserApi,
                                    final PaymentDao paymentDao,
-                                   final NonEntityDao nonEntityDao,
                                    final GlobalLocker locker,
                                    final PaymentConfig paymentConfig,
                                    @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor,
-                                   final Clock clock,
-                                   final CacheControllerDispatcher controllerDispatcher) {
-        super(pluginRegistry, accountUserApi, paymentDao, nonEntityDao, tagUserApi, locker, executor, invoiceApi, clock, controllerDispatcher);
+                                   final InternalCallContextFactory internalCallContextFactory,
+                                   final Clock clock) {
+        super(pluginRegistry, accountUserApi, paymentDao, tagUserApi, locker, executor, internalCallContextFactory, invoiceApi, clock);
         final long paymentPluginTimeoutSec = TimeUnit.SECONDS.convert(paymentConfig.getPaymentPluginTimeout().getPeriod(), paymentConfig.getPaymentPluginTimeout().getUnit());
         this.paymentPluginFormDispatcher = new PluginDispatcher<HostedPaymentPageFormDescriptor>(paymentPluginTimeoutSec, executor);
         this.paymentPluginNotificationDispatcher = new PluginDispatcher<GatewayNotification>(paymentPluginTimeoutSec, executor);
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
index 2f3e668..d179396 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -52,11 +52,10 @@ import org.killbill.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
 import org.killbill.billing.payment.provider.DefaultPaymentMethodInfoPlugin;
 import org.killbill.billing.payment.provider.ExternalPaymentProviderPlugin;
 import org.killbill.billing.tag.TagInternalApi;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.billing.util.config.PaymentConfig;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.EntityPaginationBuilder;
 import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.SourcePaginationBuilder;
@@ -87,14 +86,13 @@ public class PaymentMethodProcessor extends ProcessorBase {
                                   final AccountInternalApi accountInternalApi,
                                   final InvoiceInternalApi invoiceApi,
                                   final PaymentDao paymentDao,
-                                  final NonEntityDao nonEntityDao,
                                   final TagInternalApi tagUserApi,
                                   final GlobalLocker locker,
                                   final PaymentConfig paymentConfig,
                                   @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor,
-                                  final Clock clock,
-                                  final CacheControllerDispatcher controllerDispatcher) {
-        super(pluginRegistry, accountInternalApi, paymentDao, nonEntityDao, tagUserApi, locker, executor, invoiceApi, clock, controllerDispatcher);
+                                  final InternalCallContextFactory internalCallContextFactory,
+                                  final Clock clock) {
+        super(pluginRegistry, accountInternalApi, paymentDao, tagUserApi, locker, executor, internalCallContextFactory, invoiceApi, clock);
         final long paymentPluginTimeoutSec = TimeUnit.SECONDS.convert(paymentConfig.getPaymentPluginTimeout().getPeriod(), paymentConfig.getPaymentPluginTimeout().getUnit());
         this.uuidPluginNotificationDispatcher = new PluginDispatcher<UUID>(paymentPluginTimeoutSec, executor);
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
index f78753d..ffc9030 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -57,11 +57,9 @@ import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApiException;
 import org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin;
 import org.killbill.billing.tag.TagInternalApi;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.EntityPaginationBuilder;
 import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.SourcePaginationBuilder;
@@ -87,7 +85,6 @@ public class PaymentProcessor extends ProcessorBase {
     private static final ImmutableList<PluginProperty> PLUGIN_PROPERTIES = ImmutableList.<PluginProperty>of();
 
     private final PaymentAutomatonRunner paymentAutomatonRunner;
-    private final InternalCallContextFactory internalCallContextFactory;
 
     private static final Logger log = LoggerFactory.getLogger(PaymentProcessor.class);
 
@@ -97,15 +94,12 @@ public class PaymentProcessor extends ProcessorBase {
                             final InvoiceInternalApi invoiceApi,
                             final TagInternalApi tagUserApi,
                             final PaymentDao paymentDao,
-                            final NonEntityDao nonEntityDao,
                             final InternalCallContextFactory internalCallContextFactory,
                             final GlobalLocker locker,
                             @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor,
                             final PaymentAutomatonRunner paymentAutomatonRunner,
-                            final Clock clock,
-                            final CacheControllerDispatcher controllerDispatcher) {
-        super(pluginRegistry, accountUserApi, paymentDao, nonEntityDao, tagUserApi, locker, executor, invoiceApi, clock, controllerDispatcher);
-        this.internalCallContextFactory = internalCallContextFactory;
+                            final Clock clock) {
+        super(pluginRegistry, accountUserApi, paymentDao, tagUserApi, locker, executor, internalCallContextFactory, invoiceApi, clock);
         this.paymentAutomatonRunner = paymentAutomatonRunner;
     }
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java
index 79be2f0..a6ca074 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java
@@ -1,7 +1,8 @@
 /*
- * Copyright 2014 Groupon, Inc
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -27,7 +28,6 @@ import javax.inject.Inject;
 
 import org.killbill.automaton.MissingEntryException;
 import org.killbill.automaton.State;
-import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
@@ -48,10 +48,8 @@ import org.killbill.billing.payment.dao.PluginPropertySerializer;
 import org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException;
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.tag.TagInternalApi;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
-import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.clock.Clock;
 import org.killbill.commons.locker.GlobalLocker;
 
@@ -67,7 +65,6 @@ public class PluginRoutingPaymentProcessor extends ProcessorBase {
 
     private final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner;
     private final RetryStateMachineHelper retrySMHelper;
-    private final CacheControllerDispatcher controllerDispatcher;
 
     @Inject
     public PluginRoutingPaymentProcessor(final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
@@ -75,17 +72,15 @@ public class PluginRoutingPaymentProcessor extends ProcessorBase {
                                          final InvoiceInternalApi invoiceApi,
                                          final TagInternalApi tagUserApi,
                                          final PaymentDao paymentDao,
-                                         final NonEntityDao nonEntityDao,
                                          final GlobalLocker locker,
                                          @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor,
+                                         final InternalCallContextFactory internalCallContextFactory,
                                          final PluginRoutingPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner,
                                          final RetryStateMachineHelper retrySMHelper,
-                                         final Clock clock,
-                                         final CacheControllerDispatcher controllerDispatcher) {
-        super(pluginRegistry, accountInternalApi, paymentDao, nonEntityDao, tagUserApi, locker, executor, invoiceApi, clock, controllerDispatcher);
+                                         final Clock clock) {
+        super(pluginRegistry, accountInternalApi, paymentDao, tagUserApi, locker, executor, internalCallContextFactory, invoiceApi, clock);
         this.retrySMHelper = retrySMHelper;
         this.pluginControlledPaymentAutomatonRunner = pluginControlledPaymentAutomatonRunner;
-        this.controllerDispatcher = controllerDispatcher;
     }
 
     public Payment createAuthorization(final boolean isApiPayment, final Account account, final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency, final String paymentExternalKey, final String transactionExternalKey,
@@ -212,8 +207,7 @@ public class PluginRoutingPaymentProcessor extends ProcessorBase {
 
             final Iterable<PluginProperty> pluginProperties = PluginPropertySerializer.deserialize(attempt.getPluginProperties());
             final Account account = accountInternalApi.getAccountById(attempt.getAccountId(), internalCallContext);
-            final UUID tenantId = nonEntityDao.retrieveIdFromObject(internalCallContext.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
-            final CallContext callContext = internalCallContext.toCallContext(tenantId);
+            final CallContext callContext = buildCallContext(internalCallContext);
 
             final State state = retrySMHelper.getState(attempt.getStateName());
             pluginControlledPaymentAutomatonRunner.run(state,
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java b/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
index d9da5e2..9d70fe7 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -46,10 +46,9 @@ import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcher
 import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
 import org.killbill.billing.tag.TagInternalApi;
 import org.killbill.billing.util.api.TagApiException;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.globallocker.LockerType;
 import org.killbill.billing.util.tag.ControlTagType;
 import org.killbill.billing.util.tag.Tag;
@@ -75,10 +74,9 @@ public abstract class ProcessorBase {
     protected final GlobalLocker locker;
     protected final ExecutorService executor;
     protected final PaymentDao paymentDao;
-    protected final NonEntityDao nonEntityDao;
+    protected final InternalCallContextFactory internalCallContextFactory;
     protected final TagInternalApi tagInternalApi;
     protected final Clock clock;
-    protected final CacheControllerDispatcher controllerDispatcher;
 
     protected static final Logger log = LoggerFactory.getLogger(ProcessorBase.class);
     protected final InvoiceInternalApi invoiceApi;
@@ -86,23 +84,21 @@ public abstract class ProcessorBase {
     public ProcessorBase(final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
                          final AccountInternalApi accountInternalApi,
                          final PaymentDao paymentDao,
-                         final NonEntityDao nonEntityDao,
                          final TagInternalApi tagInternalApi,
                          final GlobalLocker locker,
                          final ExecutorService executor,
+                         final InternalCallContextFactory internalCallContextFactory,
                          final InvoiceInternalApi invoiceApi,
-                         final Clock clock,
-                         final CacheControllerDispatcher controllerDispatcher) {
+                         final Clock clock) {
         this.pluginRegistry = pluginRegistry;
         this.accountInternalApi = accountInternalApi;
         this.paymentDao = paymentDao;
-        this.nonEntityDao = nonEntityDao;
         this.locker = locker;
         this.executor = executor;
         this.tagInternalApi = tagInternalApi;
+        this.internalCallContextFactory = internalCallContextFactory;
         this.invoiceApi = invoiceApi;
         this.clock = clock;
-        this.controllerDispatcher = controllerDispatcher;
     }
 
     protected boolean isAccountAutoPayOff(final UUID accountId, final InternalTenantContext context) {
@@ -161,7 +157,11 @@ public abstract class ProcessorBase {
     }
 
     protected TenantContext buildTenantContext(final InternalTenantContext context) {
-        return context.toTenantContext(nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID)));
+        return internalCallContextFactory.createTenantContext(context);
+    }
+
+    protected CallContext buildCallContext(final InternalCallContext context) {
+        return internalCallContextFactory.createCallContext(context);
     }
 
     protected void validateUniqueTransactionExternalKey(@Nullable final String transactionExternalKey, final InternalTenantContext tenantContext) throws PaymentApiException {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryEnteringStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryEnteringStateCallback.java
index d2d0ce3..d2dd835 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryEnteringStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryEnteringStateCallback.java
@@ -1,7 +1,8 @@
 /*
- * Copyright 2014 Groupon, Inc
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -49,7 +50,7 @@ public class RetryEnteringStateCallback implements EnteringStateCallback {
         retryablePaymentAutomatonRunner.paymentDao.updatePaymentAttempt(attempt.getId(), transactionId, state.getName(), paymentStateContext.internalCallContext);
 
         if ("RETRIED".equals(state.getName())) {
-            retryServiceScheduler.scheduleRetry(ObjectType.PAYMENT_ATTEMPT, attempt.getId(), attempt.getId(),
+            retryServiceScheduler.scheduleRetry(ObjectType.PAYMENT_ATTEMPT, attempt.getId(), attempt.getId(), attempt.getTenantRecordId(),
                                                 paymentStateContext.getPaymentControlPluginNames(), paymentStateContext.getRetryDate());
         }
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentRoutingPluginApi.java b/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentRoutingPluginApi.java
index ca44ef9..5760da4 100644
--- a/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentRoutingPluginApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentRoutingPluginApi.java
@@ -1,7 +1,8 @@
 /*
- * Copyright 2014 Groupon, Inc
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -40,12 +41,12 @@ import org.killbill.billing.invoice.api.InvoicePayment;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.payment.api.TransactionType;
-import org.killbill.billing.payment.invoice.dao.InvoicePaymentRoutingDao;
-import org.killbill.billing.payment.invoice.dao.PluginAutoPayOffModelDao;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.dao.PaymentModelDao;
 import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
 import org.killbill.billing.payment.glue.PaymentModule;
+import org.killbill.billing.payment.invoice.dao.InvoicePaymentRoutingDao;
+import org.killbill.billing.payment.invoice.dao.PluginAutoPayOffModelDao;
 import org.killbill.billing.payment.retry.BaseRetryService.RetryServiceScheduler;
 import org.killbill.billing.payment.retry.DefaultFailureCallResult;
 import org.killbill.billing.payment.retry.DefaultPriorPaymentRoutingResult;
@@ -76,10 +77,10 @@ import com.google.common.collect.Iterables;
 
 public final class InvoicePaymentRoutingPluginApi implements PaymentRoutingPluginApi {
 
-    public final static String CREATED_BY = "InvoicePaymentRoutingPluginApi";
+    public static final String CREATED_BY = "InvoicePaymentRoutingPluginApi";
 
     /* Don't change value String for properties as they are referenced from jaxrs without the constants which are not accessible */
-    public final static String PLUGIN_NAME = "__INVOICE_PAYMENT_CONTROL_PLUGIN__";
+    public static final String PLUGIN_NAME = "__INVOICE_PAYMENT_CONTROL_PLUGIN__";
     public static final String PROP_IPCD_INVOICE_ID = "IPCD_INVOICE_ID";
     public static final String PROP_IPCD_REFUND_IDS_WITH_AMOUNT_KEY = "IPCD_REFUND_IDS_AMOUNTS";
     public static final String PROP_IPCD_REFUND_WITH_ADJUSTMENTS = "IPCD_REFUND_WITH_ADJUSTMENTS";
@@ -111,7 +112,7 @@ public final class InvoicePaymentRoutingPluginApi implements PaymentRoutingPlugi
     }
 
     @Override
-    public PriorPaymentRoutingResult priorCall(final PaymentRoutingContext paymentRoutingContext, Iterable<PluginProperty> properties) throws PaymentRoutingApiException {
+    public PriorPaymentRoutingResult priorCall(final PaymentRoutingContext paymentRoutingContext, final Iterable<PluginProperty> properties) throws PaymentRoutingApiException {
 
         final TransactionType transactionType = paymentRoutingContext.getTransactionType();
         Preconditions.checkArgument(transactionType == TransactionType.PURCHASE ||
@@ -132,7 +133,7 @@ public final class InvoicePaymentRoutingPluginApi implements PaymentRoutingPlugi
     }
 
     @Override
-    public OnSuccessPaymentRoutingResult onSuccessCall(final PaymentRoutingContext paymentRoutingContext, Iterable<PluginProperty> properties) throws PaymentRoutingApiException {
+    public OnSuccessPaymentRoutingResult onSuccessCall(final PaymentRoutingContext paymentRoutingContext, final Iterable<PluginProperty> properties) throws PaymentRoutingApiException {
 
         final TransactionType transactionType = paymentRoutingContext.getTransactionType();
         Preconditions.checkArgument(transactionType == TransactionType.PURCHASE ||
@@ -183,15 +184,15 @@ public final class InvoicePaymentRoutingPluginApi implements PaymentRoutingPlugi
                 default:
                     throw new IllegalStateException("Unexpected transactionType " + transactionType);
             }
-        } catch (InvoiceApiException e) {
+        } catch (final InvoiceApiException e) {
             logger.error("InvoicePaymentRoutingPluginApi onSuccessCall failed for attemptId = " + paymentRoutingContext.getAttemptPaymentId() + ", transactionType  = " + transactionType, e);
         }
         return null;
     }
 
     @Override
-    public OnFailurePaymentRoutingResult onFailureCall(final PaymentRoutingContext paymentRoutingContext, Iterable<PluginProperty> properties) throws
-                                                                                                                                               PaymentRoutingApiException {
+    public OnFailurePaymentRoutingResult onFailureCall(final PaymentRoutingContext paymentRoutingContext, final Iterable<PluginProperty> properties) throws
+                                                                                                                                                     PaymentRoutingApiException {
 
         final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentRoutingContext.getAccountId(), paymentRoutingContext);
         final TransactionType transactionType = paymentRoutingContext.getTransactionType();
@@ -210,9 +211,9 @@ public final class InvoicePaymentRoutingPluginApi implements PaymentRoutingPlugi
 
     public void process_AUTO_PAY_OFF_removal(final Account account, final InternalCallContext internalCallContext) {
         final List<PluginAutoPayOffModelDao> entries = controlDao.getAutoPayOffEntry(account.getId());
-        for (PluginAutoPayOffModelDao cur : entries) {
+        for (final PluginAutoPayOffModelDao cur : entries) {
             // TODO In theory we should pass not only PLUGIN_NAME, but also all the plugin list associated which the original call
-            retryServiceScheduler.scheduleRetry(ObjectType.ACCOUNT, account.getId(), cur.getAttemptId(), ImmutableList.<String>of(PLUGIN_NAME), clock.getUTCNow());
+            retryServiceScheduler.scheduleRetry(ObjectType.ACCOUNT, account.getId(), cur.getAttemptId(), internalCallContext.getTenantRecordId(), ImmutableList.<String>of(PLUGIN_NAME), clock.getUTCNow());
         }
         controlDao.removeAutoPayOffEntry(account.getId());
     }
@@ -245,9 +246,9 @@ public final class InvoicePaymentRoutingPluginApi implements PaymentRoutingPlugi
             } else {
                 return new DefaultPriorPaymentRoutingResult(isAborted, requestedAmount, null, null);
             }
-        } catch (InvoiceApiException e) {
+        } catch (final InvoiceApiException e) {
             throw new PaymentRoutingApiException(e);
-        } catch (IllegalArgumentException e) {
+        } catch (final IllegalArgumentException e) {
             throw new PaymentRoutingApiException(e);
         }
     }
@@ -323,7 +324,7 @@ public final class InvoicePaymentRoutingPluginApi implements PaymentRoutingPlugi
                 amountFromItems = amountFromItems.add(Objects.firstNonNull(specifiedItemAmount, itemAmount));
             }
             return amountFromItems;
-        } catch (InvoiceApiException e) {
+        } catch (final InvoiceApiException e) {
             throw new PaymentRoutingApiException(e);
         }
     }
@@ -369,12 +370,12 @@ public final class InvoicePaymentRoutingPluginApi implements PaymentRoutingPlugi
         final int attemptsInState = getNumberAttemptsInState(purchasedTransactions, TransactionStatus.PAYMENT_FAILURE);
         final int retryCount = (attemptsInState - 1) >= 0 ? (attemptsInState - 1) : 0;
         if (retryCount < retryDays.size()) {
-            int retryInDays;
+            final int retryInDays;
             final DateTime nextRetryDate = clock.getUTCNow();
             try {
                 retryInDays = retryDays.get(retryCount);
                 result = nextRetryDate.plusDays(retryInDays);
-            } catch (NumberFormatException ex) {
+            } catch (final NumberFormatException ex) {
                 logger.error("Could not get retry day for retry count {}", retryCount);
             }
         }
diff --git a/payment/src/main/java/org/killbill/billing/payment/retry/BaseRetryService.java b/payment/src/main/java/org/killbill/billing/payment/retry/BaseRetryService.java
index 659d344..21f0a3b 100644
--- a/payment/src/main/java/org/killbill/billing/payment/retry/BaseRetryService.java
+++ b/payment/src/main/java/org/killbill/billing/payment/retry/BaseRetryService.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -105,13 +105,12 @@ public abstract class BaseRetryService implements RetryService {
             this.internalCallContextFactory = internalCallContextFactory;
         }
 
-        public boolean scheduleRetry(final ObjectType objectType, final UUID objectId, final UUID attemptId, final List<String> paymentControlPluginNames, final DateTime timeOfRetry) {
-            return scheduleRetryInternal(objectType, objectId, attemptId, paymentControlPluginNames, timeOfRetry, null);
+        public boolean scheduleRetry(final ObjectType objectType, final UUID objectId, final UUID attemptId, final Long tenantRecordId, final List<String> paymentControlPluginNames, final DateTime timeOfRetry) {
+            return scheduleRetryInternal(objectType, objectId, attemptId, tenantRecordId, paymentControlPluginNames, timeOfRetry, null);
         }
 
-
-        private boolean scheduleRetryInternal(final ObjectType objectType, final UUID objectId, final UUID attemptId, final List<String> paymentControlPluginNames, final DateTime timeOfRetry, final EntitySqlDaoWrapperFactory<EntitySqlDao> transactionalDao) {
-            final InternalCallContext context = createCallContextFromPaymentId(objectType, objectId);
+        private boolean scheduleRetryInternal(final ObjectType objectType, final UUID objectId, final UUID attemptId, final Long tenantRecordId, final List<String> paymentControlPluginNames, final DateTime timeOfRetry, final EntitySqlDaoWrapperFactory<EntitySqlDao> transactionalDao) {
+            final InternalCallContext context = createCallContextFromPaymentId(objectType, objectId, tenantRecordId);
 
             try {
                 final NotificationQueue retryQueue = notificationQueueService.getNotificationQueue(DefaultPaymentService.SERVICE_NAME, getQueueName());
@@ -123,18 +122,18 @@ public abstract class BaseRetryService implements RetryService {
                         retryQueue.recordFutureNotificationFromTransaction(transactionalDao.getSqlDao(), timeOfRetry, key, context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId());
                     }
                 }
-            } catch (NoSuchNotificationQueue e) {
+            } catch (final NoSuchNotificationQueue e) {
                 log.error(String.format("Failed to retrieve notification queue %s:%s", DefaultPaymentService.SERVICE_NAME, getQueueName()));
                 return false;
-            } catch (IOException e) {
-                log.error(String.format("Failed to serialize notificationQueue event for object %s, objectId %s", objectId));
+            } catch (final IOException e) {
+                log.error(String.format("Failed to serialize notificationQueue event for objectId %s", objectId));
                 return false;
             }
             return true;
         }
 
-        protected InternalCallContext createCallContextFromPaymentId(final ObjectType objectType, final UUID objectId) {
-            return internalCallContextFactory.createInternalCallContext(objectId, objectType, PAYMENT_RETRY_SERVICE, CallOrigin.INTERNAL, UserType.SYSTEM, null);
+        protected InternalCallContext createCallContextFromPaymentId(final ObjectType objectType, final UUID objectId, final Long tenantRecordId) {
+            return internalCallContextFactory.createInternalCallContext(objectId, objectType, PAYMENT_RETRY_SERVICE, CallOrigin.INTERNAL, UserType.SYSTEM, null, tenantRecordId);
         }
 
         public abstract String getQueueName();
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestRetryablePayment.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestRetryablePayment.java
index 110bb1b..bc178c9 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestRetryablePayment.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestRetryablePayment.java
@@ -1,7 +1,8 @@
 /*
- * Copyright 2014 Groupon, Inc
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -52,6 +53,7 @@ import org.killbill.billing.payment.provider.MockPaymentRoutingProviderPlugin;
 import org.killbill.billing.payment.retry.BaseRetryService.RetryServiceScheduler;
 import org.killbill.billing.routing.plugin.api.PaymentRoutingPluginApi;
 import org.killbill.billing.tag.TagInternalApi;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.globallocker.LockerType;
 import org.killbill.commons.locker.GlobalLock;
@@ -105,6 +107,8 @@ public class TestRetryablePayment extends PaymentTestSuiteNoDB {
     private PaymentStateMachineHelper paymentSMHelper;
     @Inject
     private RetryStateMachineHelper retrySMHelper;
+    @Inject
+    private InternalCallContextFactory internalCallContextFactory;
 
     private Account account;
     private DateTime utcNow;
@@ -195,13 +199,13 @@ public class TestRetryablePayment extends PaymentTestSuiteNoDB {
                                                       null,
                                                       tagApi,
                                                       paymentDao,
-                                                      nonEntityDao,
                                                       locker,
                                                       executor,
+                                                      internalCallContextFactory,
                                                       runner,
                                                       retrySMHelper,
-                                                      clock,
-                                                      cacheControllerDispatcher);
+                                                      clock
+        );
 
     }
 
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 c6ca83b..77b50fc 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
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -27,7 +29,6 @@ import javax.annotation.Nullable;
 
 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.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -63,9 +64,9 @@ import org.killbill.billing.subscription.engine.dao.SubscriptionDao;
 import org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleModelDao;
 import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
 import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
-import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.SourcePaginationBuilder;
 import org.killbill.clock.Clock;
@@ -85,8 +86,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     private static final Logger log = LoggerFactory.getLogger(DefaultSubscriptionInternalApi.class);
 
     private final AddonUtils addonUtils;
-    private final NonEntityDao nonEntityDao;
-    private final CacheControllerDispatcher controllerDispatcher;
+    private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
     public DefaultSubscriptionInternalApi(final SubscriptionDao dao,
@@ -94,12 +94,10 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                           final Clock clock,
                                           final CatalogService catalogService,
                                           final AddonUtils addonUtils,
-                                          final NonEntityDao nonEntityDao,
-                                          final CacheControllerDispatcher controllerDispatcher) {
+                                          final InternalCallContextFactory internalCallContextFactory) {
         super(dao, apiService, clock, catalogService);
         this.addonUtils = addonUtils;
-        this.nonEntityDao = nonEntityDao;
-        this.controllerDispatcher = controllerDispatcher;
+        this.internalCallContextFactory = internalCallContextFactory;
     }
 
     @Override
@@ -128,15 +126,15 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
             final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
             final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, requestedDate, effectiveDate);
-            final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+            final CallContext callContext = internalCallContextFactory.createCallContext(context);
             return apiService.createPlan(new SubscriptionBuilder()
                                                  .setId(UUID.randomUUID())
                                                  .setBundleId(bundleId)
                                                  .setCategory(plan.getProduct().getCategory())
                                                  .setBundleStartDate(bundleStartDate)
                                                  .setAlignStartDate(effectiveDate),
-                                         plan, spec.getPhaseType(), realPriceList, requestedDate, effectiveDate, now, context.toCallContext(tenantId));
-        } catch (CatalogApiException e) {
+                                         plan, spec.getPhaseType(), realPriceList, requestedDate, effectiveDate, now, callContext);
+        } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
     }
@@ -211,11 +209,11 @@ 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) {
+        for (final SubscriptionBaseBundle cur : existingBundles) {
             final List<SubscriptionBase> subscriptions;
             try {
                 subscriptions = dao.getSubscriptions(cur.getId(), ImmutableList.<SubscriptionBaseEvent>of(), context);
-                for (SubscriptionBase s : subscriptions) {
+                for (final SubscriptionBase s : subscriptions) {
                     if (s.getCategory() == ProductCategory.ADD_ON) {
                         continue;
                     }
@@ -223,7 +221,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                         return cur;
                     }
                 }
-            } catch (CatalogApiException e) {
+            } catch (final CatalogApiException e) {
                 log.warn("Failed to get subscriptions, ", e);
                 return null;
             }
@@ -232,9 +230,9 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     }
 
     @Override
-    public List<SubscriptionBase> getSubscriptionsForBundle(UUID bundleId,
+    public List<SubscriptionBase> getSubscriptionsForBundle(final UUID bundleId,
                                                             @Nullable final DryRunArguments dryRunArguments,
-                                                            InternalTenantContext context) throws SubscriptionBaseApiException {
+                                                            final InternalTenantContext context) throws SubscriptionBaseApiException {
 
         try {
             final List<SubscriptionBaseEvent> outputDryRunEvents = new ArrayList<SubscriptionBaseEvent>();
@@ -247,7 +245,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                 outputSubscriptions.addAll(result);
             }
             return createSubscriptionsForApiUse(outputSubscriptions);
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
     }
@@ -261,36 +259,33 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                 result.put(bundleId, createSubscriptionsForApiUse(internalSubscriptions.get(bundleId)));
             }
             return result;
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
     }
 
     @Override
-    public SubscriptionBase getBaseSubscription(UUID bundleId,
-                                                InternalTenantContext context) throws SubscriptionBaseApiException {
+    public SubscriptionBase getBaseSubscription(final UUID bundleId, final InternalTenantContext context) throws SubscriptionBaseApiException {
         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) {
+        } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
     }
 
     @Override
-
-    public SubscriptionBase getSubscriptionFromId(UUID id,
-                                                  InternalTenantContext context) throws SubscriptionBaseApiException {
+    public SubscriptionBase getSubscriptionFromId(final UUID id, final InternalTenantContext context) throws SubscriptionBaseApiException {
         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) {
+        } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
     }
@@ -310,15 +305,14 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     }
 
     @Override
-    public void setChargedThroughDate(UUID subscriptionId,
-                                      DateTime chargedThruDate, InternalCallContext context) throws SubscriptionBaseApiException {
+    public void setChargedThroughDate(final UUID subscriptionId, final DateTime chargedThruDate, final 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);
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
     }
@@ -376,7 +370,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                 result.add(status);
             }
             return result;
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
 
@@ -391,7 +385,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                       @Nullable final DryRunArguments dryRunArguments,
                                       final List<SubscriptionBaseEvent> outputDryRunEvents,
                                       final List<SubscriptionBase> outputSubscriptions,
-                                      InternalTenantContext context) throws SubscriptionBaseApiException {
+                                      final InternalTenantContext context) throws SubscriptionBaseApiException {
         if (dryRunArguments == null || dryRunArguments.getAction() == null) {
             return;
         }
@@ -404,7 +398,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
             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));
+            final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
 
             if (dryRunArguments != null) {
                 switch (dryRunArguments.getAction()) {
@@ -415,7 +409,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                         final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, startEffectiveDate);
                         final UUID subscriptionId = UUID.randomUUID();
                         dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, 1L, plan, inputSpec.getPhaseType(), realPriceList,
-                                                                      utcNow, startEffectiveDate, utcNow, false, context.toTenantContext(tenantId));
+                                                                      utcNow, startEffectiveDate, utcNow, false, tenantContext);
                         final SubscriptionBuilder builder = new SubscriptionBuilder()
                                 .setId(subscriptionId)
                                 .setBundleId(bundleId)
@@ -436,12 +430,12 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                 final PlanChangeResult planChangeResult = apiService.getPlanChangeResult(subscriptionForChange,
                                                                                                          dryRunArguments.getPlanPhaseSpecifier().getProductName(),
                                                                                                          dryRunArguments.getPlanPhaseSpecifier().getBillingPeriod(),
-                                                                                                         dryRunArguments.getPlanPhaseSpecifier().getPriceListName(), utcNow, context.toTenantContext(tenantId));
+                                                                                                         dryRunArguments.getPlanPhaseSpecifier().getPriceListName(), utcNow, tenantContext);
                                 policy = planChangeResult.getPolicy();
                             }
                             changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy);
                         }
-                        dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, realPriceList, utcNow, changeEffectiveDate, utcNow, true, context.toTenantContext(tenantId));
+                        dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, realPriceList, utcNow, changeEffectiveDate, utcNow, true, tenantContext);
                         break;
 
                     case STOP_BILLING:
@@ -461,14 +455,14 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                             }
                             cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy);
                         }
-                        dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, utcNow, cancelEffectiveDate, utcNow, true, context.toTenantContext(tenantId));
+                        dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, utcNow, cancelEffectiveDate, utcNow, true, tenantContext);
                         break;
 
                     default:
                         throw new IllegalArgumentException("Unexpected dryRunArguments action " + dryRunArguments.getAction());
                 }
             }
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
         if (dryRunEvents != null && !dryRunEvents.isEmpty()) {
@@ -514,7 +508,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         return ImmutableList.<EffectiveSubscriptionInternalEvent>copyOf(Collections2.transform(transitions, new Function<SubscriptionBaseTransition, EffectiveSubscriptionInternalEvent>() {
             @Override
             @Nullable
-            public EffectiveSubscriptionInternalEvent apply(@Nullable SubscriptionBaseTransition input) {
+            public EffectiveSubscriptionInternalEvent apply(@Nullable final SubscriptionBaseTransition input) {
                 return new DefaultEffectiveSubscriptionEvent((SubscriptionBaseTransitionData) input, ((DefaultSubscriptionBase) subscription).getAlignStartDate(), null, context.getAccountRecordId(), context.getTenantRecordId());
             }
         }));
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 d91b31f..a1dcae8 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
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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
@@ -21,7 +21,6 @@ package org.killbill.billing.subscription.engine.core;
 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;
@@ -37,7 +36,6 @@ import org.killbill.billing.subscription.api.SubscriptionBaseService;
 import org.killbill.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseTransitionData;
-import org.killbill.billing.subscription.engine.addon.AddonUtils;
 import org.killbill.billing.subscription.engine.dao.SubscriptionDao;
 import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
 import org.killbill.billing.subscription.events.SubscriptionBaseEvent.EventType;
@@ -45,13 +43,10 @@ import org.killbill.billing.subscription.events.phase.PhaseEvent;
 import org.killbill.billing.subscription.events.phase.PhaseEventData;
 import org.killbill.billing.subscription.events.user.ApiEvent;
 import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.CallOrigin;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.bus.api.PersistentBus;
 import org.killbill.bus.api.PersistentBus.EventBusException;
 import org.killbill.clock.Clock;
@@ -81,17 +76,13 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
     private final InternalCallContextFactory internalCallContextFactory;
     private NotificationQueue subscriptionEventQueue;
     private final SubscriptionBaseApiService apiService;
-    private final NonEntityDao nonEntityDao;
-    private final CacheControllerDispatcher controllerDispatcher;
 
     @Inject
     public DefaultSubscriptionBaseService(final Clock clock, final SubscriptionDao dao, final PlanAligner planAligner,
                                           final PersistentBus eventBus,
                                           final NotificationQueueService notificationQueueService,
                                           final InternalCallContextFactory internalCallContextFactory,
-                                          final SubscriptionBaseApiService apiService,
-                                          final NonEntityDao nonEntityDao,
-                                          final CacheControllerDispatcher controllerDispatcher) {
+                                          final SubscriptionBaseApiService apiService) {
         this.clock = clock;
         this.dao = dao;
         this.planAligner = planAligner;
@@ -99,8 +90,6 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
         this.notificationQueueService = notificationQueueService;
         this.internalCallContextFactory = internalCallContextFactory;
         this.apiService = apiService;
-        this.nonEntityDao = nonEntityDao;
-        this.controllerDispatcher = controllerDispatcher;
     }
 
     @Override
@@ -135,7 +124,7 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
             subscriptionEventQueue = notificationQueueService.createNotificationQueue(SUBSCRIPTION_SERVICE_NAME,
                                                                                       NOTIFICATION_QUEUE_NAME,
                                                                                       queueHandler);
-        } catch (NotificationQueueAlreadyExists e) {
+        } catch (final NotificationQueueAlreadyExists e) {
             throw new RuntimeException(e);
         }
     }
@@ -159,7 +148,6 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
             return;
         }
 
-
         try {
             final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(event.getSubscriptionId(), context);
             if (subscription == null) {
@@ -178,8 +166,8 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
             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 CallContext callContext = internalCallContextFactory.createCallContext(context);
+                theRealSeqId = onBasePlanEvent(subscription, (ApiEvent) event, callContext);
             }
 
             final SubscriptionBaseTransitionData transition = (subscription.getTransitionFromEvent(event, theRealSeqId));
@@ -187,9 +175,9 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
                                                                                                       context.getUserToken(),
                                                                                                       context.getAccountRecordId(), context.getTenantRecordId());
             eventBus.post(busEvent);
-        } catch (EventBusException e) {
+        } catch (final EventBusException e) {
             log.warn("Failed to post subscription event " + event, e);
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             log.warn("Failed to post subscription event " + event, e);
         }
     }
@@ -205,7 +193,7 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
             if (nextPhaseEvent != null) {
                 dao.createNextPhaseEvent(subscription, nextPhaseEvent, context);
             }
-        } catch (SubscriptionBaseError e) {
+        } catch (final SubscriptionBaseError e) {
             log.error(String.format("Failed to insert next phase for subscription %s", subscription.getId()), e);
         }
     }
diff --git a/util/src/main/java/org/killbill/billing/util/cache/AccountRecordIdCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/AccountRecordIdCacheLoader.java
index 7562ea9..87fff3b 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/AccountRecordIdCacheLoader.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/AccountRecordIdCacheLoader.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -21,8 +23,6 @@ import java.util.UUID;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import org.skife.jdbi.v2.IDBI;
-
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.util.cache.Cachable.CacheType;
 import org.killbill.billing.util.dao.NonEntityDao;
@@ -47,6 +47,6 @@ public class AccountRecordIdCacheLoader extends BaseIdCacheLoader implements Cac
 
     @Override
     protected Object doRetrieveOperation(final String rawKey, final ObjectType objectType) {
-        return  nonEntityDao.retrieveAccountRecordIdFromObject(UUID.fromString(rawKey), objectType, null);
+        return nonEntityDao.retrieveAccountRecordIdFromObject(UUID.fromString(rawKey), objectType, null);
     }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/cache/RecordIdCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/RecordIdCacheLoader.java
index 6c78335..889057b 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/RecordIdCacheLoader.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/RecordIdCacheLoader.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -21,8 +23,6 @@ import java.util.UUID;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import org.skife.jdbi.v2.IDBI;
-
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.util.cache.Cachable.CacheType;
 import org.killbill.billing.util.dao.NonEntityDao;
@@ -35,7 +35,7 @@ public class RecordIdCacheLoader extends BaseIdCacheLoader implements CacheLoade
     private final NonEntityDao nonEntityDao;
 
     @Inject
-    public RecordIdCacheLoader(final IDBI dbi, final NonEntityDao nonEntityDao) {
+    public RecordIdCacheLoader(final NonEntityDao nonEntityDao) {
         super();
         this.nonEntityDao = nonEntityDao;
     }
diff --git a/util/src/main/java/org/killbill/billing/util/cache/TenantRecordIdCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/TenantRecordIdCacheLoader.java
index fe3d2f4..fd0501b 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/TenantRecordIdCacheLoader.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/TenantRecordIdCacheLoader.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -21,8 +23,6 @@ import java.util.UUID;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import org.skife.jdbi.v2.IDBI;
-
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.util.cache.Cachable.CacheType;
 import org.killbill.billing.util.dao.NonEntityDao;
diff --git a/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java b/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
index 71a1fe9..171aabb 100644
--- a/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
+++ b/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -48,6 +50,24 @@ public class InternalCallContextFactory {
         this.cacheControllerDispatcher = cacheControllerDispatcher;
     }
 
+    //
+    // Create contexts from internal contexts
+    //
+
+    public TenantContext createTenantContext(final InternalTenantContext context) {
+        final UUID tenantId = getTenantIdSafe(context);
+        return context.toTenantContext(tenantId);
+    }
+
+    public CallContext createCallContext(final InternalCallContext context) {
+        final UUID tenantId = getTenantIdSafe(context);
+        return context.toCallContext(tenantId);
+    }
+
+    //
+    // Create InternalTenantContext
+    //
+
     /**
      * Create an internal tenant callcontext from a tenant callcontext
      * <p/>
@@ -59,38 +79,18 @@ public class InternalCallContextFactory {
      */
     public InternalTenantContext createInternalTenantContext(final TenantContext context) {
         // If tenant id is null, this will default to the default tenant record id (multi-tenancy disabled)
-        final Long tenantRecordId = getTenantRecordId(context);
+        final Long tenantRecordId = getTenantRecordIdSafe(context);
         return createInternalTenantContext(tenantRecordId, null);
     }
 
-    /**
-     * Create an internal tenant callcontext
-     *
-     * @param tenantRecordId  tenant_record_id (cannot be null)
-     * @param accountRecordId account_record_id (cannot be null for INSERT operations)
-     * @return internal tenant callcontext
-     */
-    public InternalTenantContext createInternalTenantContext(final Long tenantRecordId, @Nullable final Long accountRecordId) {
-        //Preconditions.checkNotNull(tenantRecordId, "tenantRecordId cannot be null");
-        return new InternalTenantContext(tenantRecordId, accountRecordId);
-    }
-
     public InternalTenantContext createInternalTenantContext(final UUID accountId, final TenantContext context) {
-        final Long tenantRecordId = getTenantRecordId(context);
-        final Long accountRecordId = getAccountRecordId(accountId, ObjectType.ACCOUNT);
-        return new InternalTenantContext(tenantRecordId, accountRecordId);
+        return createInternalTenantContext(accountId, ObjectType.ACCOUNT, context);
     }
 
     public InternalTenantContext createInternalTenantContext(final UUID accountId, final InternalTenantContext context) {
         final Long tenantRecordId = context.getTenantRecordId();
-        final Long accountRecordId = getAccountRecordId(accountId, ObjectType.ACCOUNT);
-        return new InternalTenantContext(tenantRecordId, accountRecordId);
-    }
-
-    public InternalTenantContext createInternalTenantContext(final UUID accountId, final UUID objectId, final ObjectType objectType) {
-        final Long tenantRecordId = getTenantRecordId(objectId, objectType);
-        final Long accountRecordId = getAccountRecordId(accountId, ObjectType.ACCOUNT);
-        return new InternalTenantContext(tenantRecordId, accountRecordId);
+        final Long accountRecordId = getAccountRecordIdSafe(accountId, ObjectType.ACCOUNT, context.getTenantRecordId());
+        return createInternalTenantContext(tenantRecordId, accountRecordId);
     }
 
     /**
@@ -104,34 +104,30 @@ public class InternalCallContextFactory {
     public InternalTenantContext createInternalTenantContext(final UUID objectId, final ObjectType objectType, final TenantContext context) {
         // The callcontext may come from a user API - for security, check we're not doing cross-tenants operations
         //final Long tenantRecordIdFromObject = retrieveTenantRecordIdFromObject(objectId, objectType);
-        //final Long tenantRecordIdFromContext = getTenantRecordId(callcontext);
+        //final Long tenantRecordIdFromContext = getTenantRecordIdSafe(callcontext);
         //Preconditions.checkState(tenantRecordIdFromContext.equals(tenantRecordIdFromObject),
         //                         "tenant of the pointed object (%s) and the callcontext (%s) don't match!", tenantRecordIdFromObject, tenantRecordIdFromContext);
-        final Long tenantRecordId = getTenantRecordId(context);
-        final Long accountRecordId = getAccountRecordId(objectId, objectType);
+        final Long tenantRecordId = getTenantRecordIdSafe(context);
+        final Long accountRecordId = getAccountRecordIdSafe(objectId, objectType, context);
         return createInternalTenantContext(tenantRecordId, accountRecordId);
     }
 
     /**
-     * Create an internal call callcontext from a call callcontext, and retrieving the account_record_id from another table
+     * Create an internal tenant callcontext
      *
-     * @param objectId   the id of the row in the table pointed by object type where to look for account_record_id
-     * @param objectType the object type pointed by this objectId
-     * @param context    original call callcontext
-     * @return internal call callcontext from callcontext, with a non null account_record_id (if found)
+     * @param tenantRecordId  tenant_record_id (cannot be null)
+     * @param accountRecordId account_record_id (cannot be null for INSERT operations)
+     * @return internal tenant callcontext
      */
-    public InternalCallContext createInternalCallContext(final UUID objectId, final ObjectType objectType, final CallContext context) {
-        // The callcontext may come from a user API - for security, check we're not doing cross-tenants operations
-        //final Long tenantRecordIdFromObject = retrieveTenantRecordIdFromObject(objectId, objectType);
-        //final Long tenantRecordIdFromContext = getTenantRecordId(callcontext);
-        //Preconditions.checkState(tenantRecordIdFromContext.equals(tenantRecordIdFromObject),
-        //                         "tenant of the pointed object (%s) and the callcontext (%s) don't match!", tenantRecordIdFromObject, tenantRecordIdFromContext);
-
-        return createInternalCallContext(objectId, objectType, context.getUserName(), context.getCallOrigin(),
-                                         context.getUserType(), context.getUserToken(), context.getReasonCode(), context.getComments(),
-                                         context.getCreatedDate(), context.getUpdatedDate());
+    public InternalTenantContext createInternalTenantContext(final Long tenantRecordId, @Nullable final Long accountRecordId) {
+        //Preconditions.checkNotNull(tenantRecordId, "tenantRecordId cannot be null");
+        return new InternalTenantContext(tenantRecordId, accountRecordId);
     }
 
+    //
+    // Create InternalCallContext
+    //
+
     /**
      * Create an internal call callcontext using an existing account to retrieve tenant and account record ids
      * <p/>
@@ -142,50 +138,35 @@ public class InternalCallContextFactory {
      * @return internal call callcontext
      */
     public InternalCallContext createInternalCallContext(final UUID accountId, final CallContext context) {
-        return createInternalCallContext(accountId, ObjectType.ACCOUNT, context.getUserName(), context.getCallOrigin(),
-                                         context.getUserType(), context.getUserToken(), context.getReasonCode(), context.getComments(),
-                                         context.getCreatedDate(), context.getUpdatedDate());
-    }
-
-    /**
-     * Create an internal call callcontext using an existing account to retrieve tenant and account record ids
-     *
-     * @param accountId  account id
-     * @param userName   user name
-     * @param callOrigin call origin
-     * @param userType   user type
-     * @param userToken  user token, if any
-     * @return internal call callcontext
-     */
-    public InternalCallContext createInternalCallContext(final UUID accountId, final String userName, final CallOrigin callOrigin,
-                                                         final UserType userType, @Nullable final UUID userToken) {
-        return createInternalCallContext(accountId, ObjectType.ACCOUNT, userName, callOrigin, userType, userToken);
+        return createInternalCallContext(accountId, ObjectType.ACCOUNT, context);
     }
 
     /**
-     * Create an internal call callcontext using an existing object to retrieve tenant and account record ids
+     * Create an internal call callcontext from a call callcontext, and retrieving the account_record_id from another table
      *
      * @param objectId   the id of the row in the table pointed by object type where to look for account_record_id
      * @param objectType the object type pointed by this objectId
-     * @param userName   user name
-     * @param callOrigin call origin
-     * @param userType   user type
-     * @param userToken  user token, if any
-     * @return internal call callcontext
+     * @param context    original call callcontext
+     * @return internal call callcontext from callcontext, with a non null account_record_id (if found)
      */
-    public InternalCallContext createInternalCallContext(final UUID objectId, final ObjectType objectType, final String userName,
-                                                         final CallOrigin callOrigin, final UserType userType, @Nullable final UUID userToken) {
-        return createInternalCallContext(objectId, objectType, userName, callOrigin, userType, userToken, null, null, clock.getUTCNow(), clock.getUTCNow());
+    public InternalCallContext createInternalCallContext(final UUID objectId, final ObjectType objectType, final CallContext context) {
+        // The callcontext may come from a user API - for security, check we're not doing cross-tenants operations
+        //final Long tenantRecordIdFromObject = retrieveTenantRecordIdFromObject(objectId, objectType);
+        //final Long tenantRecordIdFromContext = getTenantRecordIdSafe(callcontext);
+        //Preconditions.checkState(tenantRecordIdFromContext.equals(tenantRecordIdFromObject),
+        //                         "tenant of the pointed object (%s) and the callcontext (%s) don't match!", tenantRecordIdFromObject, tenantRecordIdFromContext);
+
+        return createInternalCallContext(objectId, objectType, context.getUserName(), context.getCallOrigin(),
+                                         context.getUserType(), context.getUserToken(), context.getReasonCode(), context.getComments(),
+                                         context.getCreatedDate(), context.getUpdatedDate(), context);
     }
 
+    // Used by the payment retry service
     public InternalCallContext createInternalCallContext(final UUID objectId, final ObjectType objectType, final String userName,
-                                                         final CallOrigin callOrigin, final UserType userType, @Nullable final UUID userToken,
-                                                         @Nullable final String reasonCode, @Nullable final String comment, final DateTime createdDate,
-                                                         final DateTime updatedDate) {
-        final Long tenantRecordId = nonEntityDao.retrieveTenantRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.TENANT_RECORD_ID));
-        final Long accountRecordId = getAccountRecordId(objectId, objectType);
+                                                         final CallOrigin callOrigin, final UserType userType, @Nullable final UUID userToken, final Long tenantRecordId) {
+        final Long accountRecordId = getAccountRecordIdSafe(objectId, objectType, tenantRecordId);
         return createInternalCallContext(tenantRecordId, accountRecordId, userName, callOrigin, userType, userToken,
-                                         reasonCode, comment, createdDate, updatedDate);
+                                         null, null, clock.getUTCNow(), clock.getUTCNow());
     }
 
     /**
@@ -207,17 +188,6 @@ public class InternalCallContextFactory {
                                        clock.getUTCNow(), clock.getUTCNow());
     }
 
-    private InternalCallContext createInternalCallContext(@Nullable final Long tenantRecordId, final Long accountRecordId, final String userName,
-                                                          final CallOrigin callOrigin, final UserType userType, @Nullable final UUID userToken,
-                                                          @Nullable final String reasonCode, @Nullable final String comment, final DateTime createdDate,
-                                                          final DateTime updatedDate) {
-        //Preconditions.checkNotNull(accountRecordId, "accountRecordId cannot be null");
-        final Long nonNulTenantRecordId = Objects.firstNonNull(tenantRecordId, INTERNAL_TENANT_RECORD_ID);
-
-        return new InternalCallContext(nonNulTenantRecordId, accountRecordId, userToken, userName, callOrigin, userType, reasonCode, comment,
-                                       createdDate, updatedDate);
-    }
-
     /**
      * Create an internal call callcontext without populating the account record id
      * <p/>
@@ -229,7 +199,7 @@ public class InternalCallContextFactory {
      */
     public InternalCallContext createInternalCallContext(final CallContext context) {
         // If tenant id is null, this will default to the default tenant record id (multi-tenancy disabled)
-        final Long tenantRecordId = getTenantRecordId(context);
+        final Long tenantRecordId = getTenantRecordIdSafe(context);
         return new InternalCallContext(tenantRecordId, null, context);
     }
 
@@ -240,32 +210,119 @@ public class InternalCallContextFactory {
                                        context.getCreatedDate(), context.getUpdatedDate());
     }
 
-    // Used when we need to re-hydrate the callcontext with the tenant_record_id and account_record_id (when claiming bus events)
-    public InternalCallContext createInternalCallContext(final Long tenantRecordId, final Long accountRecordId, final InternalCallContext context) {
-        return new InternalCallContext(tenantRecordId, accountRecordId, context.getUserToken(), context.getCreatedBy(),
-                                       context.getCallOrigin(), context.getContextUserType(), context.getReasonCode(), context.getComments(),
-                                       context.getCreatedDate(), context.getUpdatedDate());
+    private InternalCallContext createInternalCallContext(final UUID objectId, final ObjectType objectType, final String userName,
+                                                          final CallOrigin callOrigin, final UserType userType, @Nullable final UUID userToken,
+                                                          @Nullable final String reasonCode, @Nullable final String comment, final DateTime createdDate,
+                                                          final DateTime updatedDate, final TenantContext tenantContext) {
+        final Long tenantRecordId = getTenantRecordIdSafe(objectId, objectType, tenantContext);
+        final Long accountRecordId = getAccountRecordIdSafe(objectId, objectType, tenantContext);
+        return createInternalCallContext(tenantRecordId, accountRecordId, userName, callOrigin, userType, userToken,
+                                         reasonCode, comment, createdDate, updatedDate);
     }
 
-    private Long getAccountRecordId(final UUID accountId) {
-        return getAccountRecordId(accountId, ObjectType.ACCOUNT);
+    private InternalCallContext createInternalCallContext(@Nullable final Long tenantRecordId, final Long accountRecordId, final String userName,
+                                                          final CallOrigin callOrigin, final UserType userType, @Nullable final UUID userToken,
+                                                          @Nullable final String reasonCode, @Nullable final String comment, final DateTime createdDate,
+                                                          final DateTime updatedDate) {
+        //Preconditions.checkNotNull(accountRecordId, "accountRecordId cannot be null");
+        final Long nonNulTenantRecordId = Objects.firstNonNull(tenantRecordId, INTERNAL_TENANT_RECORD_ID);
+
+        return new InternalCallContext(nonNulTenantRecordId, accountRecordId, userToken, userName, callOrigin, userType, reasonCode, comment,
+                                       createdDate, updatedDate);
     }
 
-    private Long getAccountRecordId(final UUID objectId, final ObjectType objectType) {
-        return nonEntityDao.retrieveAccountRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
+    //
+    // Safe NonEntityDao public wrappers
+    //
+
+    // Safe method to retrieve the account id from any object
+    public UUID getAccountId(final UUID objectId, final ObjectType objectType, final TenantContext context) {
+        final Long accountRecordId = getAccountRecordIdSafe(objectId, objectType, context);
+        if (accountRecordId != null) {
+            return nonEntityDao.retrieveIdFromObject(accountRecordId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+        } else {
+            return null;
+        }
     }
 
-    private Long getTenantRecordId(final UUID objectId, final ObjectType objectType) {
-        return nonEntityDao.retrieveTenantRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.TENANT_RECORD_ID));
+    // Safe method to retrieve the record id from any object (should only be used by DefaultRecordIdApi)
+    public Long getRecordIdFromObject(final UUID objectId, final ObjectType objectType, final TenantContext context) {
+        if (objectBelongsToTheRightTenant(objectId, objectType, context)) {
+            return nonEntityDao.retrieveRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+        } else {
+            return null;
+        }
+    }
+
+    //
+    // Safe NonEntityDao private wrappers
+    //
+
+    private Long getAccountRecordIdSafe(final UUID objectId, final ObjectType objectType, final TenantContext context) {
+        if (objectBelongsToTheRightTenant(objectId, objectType, context)) {
+            return getAccountRecordIdUnsafe(objectId, objectType);
+        } else {
+            return null;
+        }
+    }
+
+    private Long getAccountRecordIdSafe(final UUID objectId, final ObjectType objectType, final Long tenantRecordId) {
+        if (objectBelongsToTheRightTenant(objectId, objectType, tenantRecordId)) {
+            return getAccountRecordIdUnsafe(objectId, objectType);
+        } else {
+            return null;
+        }
+    }
+
+    private Long getTenantRecordIdSafe(final UUID objectId, final ObjectType objectType, final TenantContext context) {
+        if (objectBelongsToTheRightTenant(objectId, objectType, context)) {
+            return getTenantRecordIdUnsafe(objectId, objectType);
+        } else {
+            return null;
+        }
     }
 
-    private Long getTenantRecordId(final TenantContext context) {
+    private Long getTenantRecordIdSafe(final TenantContext context) {
+        return getTenantRecordIdSafe(context.getTenantId());
+    }
+
+    private Long getTenantRecordIdSafe(final UUID tenantId) {
         // Default to single default tenant (e.g. single tenant mode)
         // TODO Extract this convention (e.g. BusinessAnalyticsBase needs to know about it)
-        if (context.getTenantId() == null) {
+        if (tenantId == null) {
             return INTERNAL_TENANT_RECORD_ID;
         } else {
-            return nonEntityDao.retrieveTenantRecordIdFromObject(context.getTenantId(), ObjectType.TENANT, cacheControllerDispatcher.getCacheController(CacheType.TENANT_RECORD_ID));
+            return getTenantRecordIdUnsafe(tenantId, ObjectType.TENANT);
         }
     }
+
+    private UUID getTenantIdSafe(final InternalTenantContext context) {
+        return nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+    }
+
+    //
+    // In-code tenant checkers
+    //
+
+    private boolean objectBelongsToTheRightTenant(final UUID objectId, final ObjectType objectType, final TenantContext context) {
+        final Long realTenantRecordId = getTenantRecordIdSafe(context);
+        return objectBelongsToTheRightTenant(objectId, objectType, realTenantRecordId);
+    }
+
+    private boolean objectBelongsToTheRightTenant(final UUID objectId, final ObjectType objectType, final Long realTenantRecordId) {
+        final Long objectTenantRecordId = getTenantRecordIdUnsafe(objectId, objectType);
+        return realTenantRecordId != null && realTenantRecordId.equals(objectTenantRecordId);
+    }
+
+    //
+    // Unsafe methods - no context is validated
+    //
+
+    private Long getAccountRecordIdUnsafe(final UUID objectId, final ObjectType objectType) {
+        return nonEntityDao.retrieveAccountRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
+    }
+
+    private Long getTenantRecordIdUnsafe(final UUID objectId, final ObjectType objectType) {
+        return nonEntityDao.retrieveTenantRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.TENANT_RECORD_ID));
+    }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/dao/NonEntityDao.java b/util/src/main/java/org/killbill/billing/util/dao/NonEntityDao.java
index e3dec90..600cb97 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/NonEntityDao.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/NonEntityDao.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -22,8 +24,8 @@ import javax.annotation.Nullable;
 
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.util.cache.CacheController;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 
+// This should only be used for internal operations (trusted code, not API), because the context will not be validated!
 public interface NonEntityDao {
 
     public Long retrieveRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache);
diff --git a/util/src/main/java/org/killbill/billing/util/recordid/DefaultRecordIdApi.java b/util/src/main/java/org/killbill/billing/util/recordid/DefaultRecordIdApi.java
index cc8a7ab..9fca345 100644
--- a/util/src/main/java/org/killbill/billing/util/recordid/DefaultRecordIdApi.java
+++ b/util/src/main/java/org/killbill/billing/util/recordid/DefaultRecordIdApi.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
  *
@@ -22,25 +24,20 @@ import javax.inject.Inject;
 
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.util.api.RecordIdApi;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
-import org.killbill.billing.util.dao.NonEntityDao;
 
-public class DefaultRecordIdApi implements RecordIdApi  {
+public class DefaultRecordIdApi implements RecordIdApi {
 
-    private final NonEntityDao nonEntityDao;
-    private final CacheControllerDispatcher cacheControllerDispatcher;
+    private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
-    public DefaultRecordIdApi(final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
-        this.nonEntityDao = nonEntityDao;
-        this.cacheControllerDispatcher = cacheControllerDispatcher;
+    public DefaultRecordIdApi(final InternalCallContextFactory internalCallContextFactory) {
+        this.internalCallContextFactory = internalCallContextFactory;
     }
 
-
     @Override
     public Long getRecordId(final UUID objectId, final ObjectType objectType, final TenantContext tenantContext) {
-        return nonEntityDao.retrieveRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+        return internalCallContextFactory.getRecordIdFromObject(objectId, objectType, tenantContext);
     }
 }