killbill-uncached

Changes

pom.xml 8(+8 -0)

util/pom.xml 5(+5 -0)

Details

diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailModelDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailModelDao.java
index 375ea7f..ec671b7 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailModelDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailModelDao.java
@@ -105,4 +105,9 @@ public class AccountEmailModelDao extends EntityBase implements EntityModelDao<A
     public TableName getTableName() {
         return TableName.ACCOUNT_EMAIL;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.ACCOUNT_EMAIL_HISTORY;
+    }
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountModelDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountModelDao.java
index 95e6aaa..e9266ed 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountModelDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountModelDao.java
@@ -318,4 +318,9 @@ public class AccountModelDao extends EntityBase implements EntityModelDao<Accoun
     public TableName getTableName() {
         return TableName.ACCOUNT;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.ACCOUNT_HISTORY;
+    }
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
index 18e2ac3..c5c0513 100644
--- a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
@@ -30,9 +30,12 @@ import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
 import com.ning.billing.util.audit.ChangeType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.entity.dao.EntityDaoBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
@@ -54,8 +57,9 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
     private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
-    public DefaultAccountDao(final IDBI dbi, final InternalBus eventBus, final InternalCallContextFactory internalCallContextFactory) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi), AccountSqlDao.class);
+    public DefaultAccountDao(final IDBI dbi, final InternalBus eventBus, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+                             final InternalCallContextFactory internalCallContextFactory, final NonEntityDao nonEntityDao) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), AccountSqlDao.class);
         this.eventBus = eventBus;
         this.internalCallContextFactory = internalCallContextFactory;
     }
diff --git a/account/src/test/java/com/ning/billing/account/AccountTestBase.java b/account/src/test/java/com/ning/billing/account/AccountTestBase.java
index 6d9acdb..4d85d51 100644
--- a/account/src/test/java/com/ning/billing/account/AccountTestBase.java
+++ b/account/src/test/java/com/ning/billing/account/AccountTestBase.java
@@ -39,12 +39,15 @@ import com.ning.billing.util.audit.dao.AuditDao;
 import com.ning.billing.util.audit.dao.DefaultAuditDao;
 import com.ning.billing.util.bus.DefaultBusService;
 import com.ning.billing.util.bus.InMemoryInternalBus;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.customfield.dao.CustomFieldDao;
 import com.ning.billing.util.customfield.dao.DefaultCustomFieldDao;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.svcsapi.bus.BusService;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.tag.api.user.TagEventBuilder;
@@ -66,6 +69,8 @@ public abstract class AccountTestBase extends AccountTestSuiteWithEmbeddedDB {
     protected CustomFieldDao customFieldDao;
     protected TagDefinitionDao tagDefinitionDao;
     protected TagDao tagDao;
+    protected CacheControllerDispatcher controllerDispatcher;
+    protected NonEntityDao nonEntityDao;
 
     protected AccountUserApi accountUserApi;
 
@@ -74,12 +79,15 @@ public abstract class AccountTestBase extends AccountTestSuiteWithEmbeddedDB {
         try {
             final IDBI dbi = getDBI();
 
-            final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(dbi, clock);
-            accountDao = new DefaultAccountDao(dbi, bus, internalCallContextFactory);
+            controllerDispatcher = new CacheControllerDispatcher();
+            nonEntityDao = new DefaultNonEntityDao(dbi);
+            final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(clock, nonEntityDao, controllerDispatcher);
+            accountDao = new DefaultAccountDao(dbi, bus, clock, controllerDispatcher, internalCallContextFactory, nonEntityDao);
             auditDao = new DefaultAuditDao(dbi);
-            customFieldDao = new DefaultCustomFieldDao(dbi);
-            tagDefinitionDao = new DefaultTagDefinitionDao(dbi, tagEventBuilder, bus);
-            tagDao = new DefaultTagDao(dbi, tagEventBuilder, bus);
+            customFieldDao = new DefaultCustomFieldDao(dbi, clock, controllerDispatcher, nonEntityDao);
+            tagDefinitionDao = new DefaultTagDefinitionDao(dbi, tagEventBuilder, bus, clock, controllerDispatcher, nonEntityDao);
+
+            tagDao = new DefaultTagDao(dbi, tagEventBuilder, bus, clock, controllerDispatcher, nonEntityDao);
 
             // Health check test to make sure MySQL is setup properly
             accountDao.test(internalCallContext);
@@ -152,6 +160,7 @@ public abstract class AccountTestBase extends AccountTestSuiteWithEmbeddedDB {
     }
 
     private AccountData createAccountData(final int billCycleDayUTC, final int billCycleDayLocal, final String phone) {
+
         final String externalKey = UUID.randomUUID().toString();
         final String email = UUID.randomUUID().toString().substring(0, 4) + '@' + UUID.randomUUID().toString().substring(0, 4);
         final String name = UUID.randomUUID().toString();
diff --git a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
index bd4e9c6..3f4841a 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
@@ -32,9 +32,11 @@ import com.ning.billing.util.email.EmailModule;
 import com.ning.billing.util.email.templates.TemplateModule;
 import com.ning.billing.util.globallocker.TestGlobalLockerModule;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
 import com.ning.billing.util.glue.ClockModule;
 import com.ning.billing.util.glue.CustomFieldModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
@@ -60,6 +62,8 @@ public class AnalyticsTestModule extends AnalyticsModule {
         install(new TagStoreModule());
         install(new NotificationQueueModule());
         install(new DefaultJunctionModule());
+        install(new CacheModule());
+        install(new NonEntityDaoModule());
 
         // Install the Dao layer
         final IDBI dbi = KillbillTestSuiteWithEmbeddedDB.getDBI();
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
index 783ef2c..03eecba 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
@@ -59,10 +59,13 @@ import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.mock.MockPlan;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
 import com.ning.billing.util.svcapi.payment.PaymentInternalApi;
 import com.ning.billing.util.svcapi.tag.TagInternalApi;
@@ -84,6 +87,7 @@ public class TestDefaultAnalyticsUserApi extends AnalyticsTestSuiteWithEmbeddedD
     @BeforeMethod(groups = "mysql")
     public void setUp() throws Exception {
         final IDBI dbi = helper.getDBI();
+        final NonEntityDao nonEntityDao = new DefaultNonEntityDao(dbi);
         accountSqlDao = dbi.onDemand(BusinessAccountSqlDao.class);
         subscriptionTransitionSqlDao = dbi.onDemand(BusinessSubscriptionTransitionSqlDao.class);
         invoiceSqlDao = dbi.onDemand(BusinessInvoiceSqlDao.class);
@@ -104,7 +108,7 @@ public class TestDefaultAnalyticsUserApi extends AnalyticsTestSuiteWithEmbeddedD
                                                        Mockito.mock(EntitlementInternalApi.class),
                                                        Mockito.mock(PaymentInternalApi.class),
                                                        Mockito.mock(TagInternalApi.class),
-                                                       new InternalCallContextFactory(dbi, clock));
+                                                       new InternalCallContextFactory(clock, nonEntityDao, new CacheControllerDispatcher()));
     }
 
     @Test(groups = "mysql")
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
index cd1877a..f412b9f 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
@@ -51,11 +51,14 @@ import com.ning.billing.entitlement.engine.dao.DefaultEntitlementDao;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.mock.MockAccountBuilder;
 import com.ning.billing.util.bus.InMemoryInternalBus;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.CatalogConfig;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.notificationq.DefaultNotificationQueueService;
 import com.ning.billing.util.notificationq.NotificationQueueConfig;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
@@ -73,7 +76,7 @@ public class TestBusinessTagRecorder extends AnalyticsTestSuiteWithEmbeddedDB {
     private EntitlementInternalApi entitlementApi;
     private EntitlementUserApi entitlementUserApi;
     private BusinessTagDao tagDao;
-
+    private CacheControllerDispatcher controllerDispatcher;
 
     private NotificationQueueConfig config = new NotificationQueueConfig() {
         @Override
@@ -96,20 +99,22 @@ public class TestBusinessTagRecorder extends AnalyticsTestSuiteWithEmbeddedDB {
     public void setUp() throws Exception {
         final Clock clock = new ClockMock();
         final IDBI dbi = helper.getDBI();
+        controllerDispatcher = new CacheControllerDispatcher();
+        final NonEntityDao nonEntityDao = new DefaultNonEntityDao(dbi);
         accountTagSqlDao = dbi.onDemand(BusinessAccountTagSqlDao.class);
         final BusinessInvoiceTagSqlDao invoiceTagSqlDao = dbi.onDemand(BusinessInvoiceTagSqlDao.class);
         final BusinessInvoicePaymentTagSqlDao invoicePaymentTagSqlDao = dbi.onDemand(BusinessInvoicePaymentTagSqlDao.class);
         subscriptionTransitionTagSqlDao = dbi.onDemand(BusinessSubscriptionTransitionTagSqlDao.class);
         eventBus = new InMemoryInternalBus();
-        final AccountDao accountDao = new DefaultAccountDao(dbi, eventBus, new InternalCallContextFactory(dbi, new ClockMock()));
+        final AccountDao accountDao = new DefaultAccountDao(dbi, eventBus, clock, controllerDispatcher, new InternalCallContextFactory(new ClockMock(), nonEntityDao, controllerDispatcher), nonEntityDao);
         callContextFactory = new DefaultCallContextFactory(clock);
-        final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(dbi, clock);
+        final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(clock, nonEntityDao, controllerDispatcher);
         accountApi = new DefaultAccountInternalApi(accountDao);
         accountUserApi = new DefaultAccountUserApi(callContextFactory, internalCallContextFactory, accountDao);
         final CatalogService catalogService = new DefaultCatalogService(Mockito.mock(CatalogConfig.class), Mockito.mock(VersionedCatalogLoader.class));
         final AddonUtils addonUtils = new AddonUtils(catalogService);
-        final DefaultNotificationQueueService notificationQueueService = new DefaultNotificationQueueService(dbi, clock, config, internalCallContextFactory);
-        final EntitlementDao entitlementDao = new DefaultEntitlementDao(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService);
+        final DefaultNotificationQueueService notificationQueueService = new DefaultNotificationQueueService(dbi, clock, config, internalCallContextFactory, nonEntityDao, controllerDispatcher);
+        final EntitlementDao entitlementDao = new DefaultEntitlementDao(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService, controllerDispatcher, nonEntityDao);
         final PlanAligner planAligner = new PlanAligner(catalogService);
         final DefaultSubscriptionApiService apiService = new DefaultSubscriptionApiService(clock, entitlementDao, catalogService, planAligner, addonUtils, internalCallContextFactory);
         entitlementApi = new DefaultEntitlementInternalApi(entitlementDao, apiService, clock, catalogService);
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
index 982b63c..10b04fe 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
@@ -62,8 +62,10 @@ import com.ning.billing.util.email.templates.TemplateModule;
 import com.ning.billing.util.globallocker.TestGlobalLockerModule;
 import com.ning.billing.util.glue.AuditModule;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
 import com.ning.billing.util.glue.CustomFieldModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.svcsapi.bus.BusService;
@@ -99,6 +101,7 @@ public class BeatrixIntegrationModule extends AbstractModule {
         }
         bind(IDBI.class).toInstance(dbi);
 
+        install(new CacheModule());
         install(new EmailModule());
         install(new CallContextModule());
         install(new TestGlobalLockerModule(helper));
@@ -116,6 +119,7 @@ public class BeatrixIntegrationModule extends AbstractModule {
         install(new DefaultJunctionModule());
         install(new IntegrationTestOverdueModule());
         install(new AuditModule());
+        install(new NonEntityDaoModule());
 
         bind(AccountChecker.class).asEagerSingleton();
         bind(EntitlementChecker.class).asEagerSingleton();
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/util/AuditChecker.java b/beatrix/src/test/java/com/ning/billing/beatrix/util/AuditChecker.java
index ec8e8cf..4d779c9 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/util/AuditChecker.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/util/AuditChecker.java
@@ -53,6 +53,8 @@ import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.Entity;
 import com.ning.billing.util.entity.dao.EntityModelDao;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
@@ -66,13 +68,15 @@ public class AuditChecker {
     private final AuditUserApi auditUserApi;
     private final IDBI dbi;
     private final InternalCallContextFactory callContextFactory;
+    private final NonEntityDao nonEntityDao;
 
 
     @Inject
-    public AuditChecker(final AuditUserApi auditUserApi, final IDBI dbi, final InternalCallContextFactory callContextFactory) {
+    public AuditChecker(final AuditUserApi auditUserApi, final IDBI dbi, final InternalCallContextFactory callContextFactory, final NonEntityDao nonEntityDao) {
         this.auditUserApi = auditUserApi;
         this.dbi = dbi;
         this.callContextFactory = callContextFactory;
+        this.nonEntityDao = nonEntityDao;
     }
 
 
@@ -205,24 +209,28 @@ public class AuditChecker {
             // We can't take userToken oustide of the 'if' because for instance NextBillingDate invoice will not have it.
             Assert.assertEquals(auditLog.getUserToken(), context.getUserToken().toString());
         }
-        final M entityModel = extractEntityModelFromEntityWithTargetRecordId(auditLog.getId(), sqlDao, context, useHistory);
+        final M entityModel = extractEntityModelFromEntityWithTargetRecordId(entityId, auditLog.getId(), sqlDao, context, useHistory);
         Assert.assertEquals(entityModel.getId(), entityId);
 
     }
 
 
-    private <T extends EntitySqlDao<M, E>, M extends EntityModelDao<E>, E extends Entity> M extractEntityModelFromEntityWithTargetRecordId(final UUID entityId, final Class<T> sqlDao, final CallContext context, final boolean useHistory) {
+    private <T extends EntitySqlDao<M, E>, M extends EntityModelDao<E>, E extends Entity> M extractEntityModelFromEntityWithTargetRecordId(final UUID entityId, final UUID auditLogId, final Class<T> sqlDao, final CallContext context, final boolean useHistory) {
+
+
+        final M modelDaoThatGivesMeTableName = dbi.onDemand(sqlDao).getById(entityId.toString(), callContextFactory.createInternalCallContext(context));
+
         Integer targetRecordId = dbi.withHandle(new HandleCallback<Integer>() {
             @Override
             public Integer withHandle(final Handle handle) throws Exception {
 
-                List<Map<String, Object>> res = handle.select("select target_record_id from audit_log where id = '" + entityId.toString() + "';");
+                List<Map<String, Object>> res = handle.select("select target_record_id from audit_log where id = '" + auditLogId.toString() + "';");
                 return (Integer) res.get(0).get("target_record_id");
             }
         });
 
         if (useHistory) {
-            Long entityRecordId =  dbi.onDemand(sqlDao).getHistoryTargetRecordId(Long.valueOf(targetRecordId), callContextFactory.createInternalCallContext(context));
+            Long entityRecordId = nonEntityDao.retrieveHistoryTargetRecordId(Long.valueOf(targetRecordId), modelDaoThatGivesMeTableName.getHistoryTableName());
             targetRecordId = new Integer(entityRecordId.intValue());
         }
         return dbi.onDemand(sqlDao).getByRecordId(Long.valueOf(targetRecordId), callContextFactory.createInternalCallContext(context));
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/DefaultEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/DefaultEntitlementDao.java
index 6aeafe5..a55cb46 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/DefaultEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/DefaultEntitlementDao.java
@@ -70,9 +70,11 @@ import com.ning.billing.entitlement.events.user.ApiEventChange;
 import com.ning.billing.entitlement.events.user.ApiEventMigrateBilling;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -105,9 +107,10 @@ public class DefaultEntitlementDao implements EntitlementDao {
 
     @Inject
     public DefaultEntitlementDao(final IDBI dbi, final Clock clock, final AddonUtils addonUtils,
-                                 final NotificationQueueService notificationQueueService, final InternalBus eventBus, final CatalogService catalogService) {
+                                 final NotificationQueueService notificationQueueService, final InternalBus eventBus, final CatalogService catalogService,
+                                 final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
         this.clock = clock;
-        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi);
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
         this.notificationQueueService = notificationQueueService;
         this.addonUtils = addonUtils;
         this.eventBus = eventBus;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/EntitlementEventModelDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/EntitlementEventModelDao.java
index 029b78a..f85b5e8 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/EntitlementEventModelDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/EntitlementEventModelDao.java
@@ -287,4 +287,9 @@ public class EntitlementEventModelDao extends EntityBase implements EntityModelD
     public TableName getTableName() {
         return TableName.SUBSCRIPTION_EVENTS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/SubscriptionBundleModelDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/SubscriptionBundleModelDao.java
index 10612c9..2a49d23 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/SubscriptionBundleModelDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/SubscriptionBundleModelDao.java
@@ -116,4 +116,10 @@ public class SubscriptionBundleModelDao extends EntityBase implements EntityMode
     public TableName getTableName() {
         return TableName.BUNDLES;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
+
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/SubscriptionModelDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/SubscriptionModelDao.java
index b208f18..c68f65e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/SubscriptionModelDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/SubscriptionModelDao.java
@@ -175,4 +175,10 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
     public TableName getTableName() {
         return TableName.SUBSCRIPTIONS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
+
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestDefaultEntitlementTransferApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestDefaultEntitlementTransferApi.java
index cf792cc..88efe2b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestDefaultEntitlementTransferApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestDefaultEntitlementTransferApi.java
@@ -46,9 +46,11 @@ import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.user.ApiEventTransfer;
 import com.ning.billing.entitlement.events.user.ApiEventType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.collect.ImmutableList;
 
@@ -61,11 +63,12 @@ public class TestDefaultEntitlementTransferApi extends EntitlementTestSuite {
 
     @BeforeMethod(groups = "fast")
     public void setUp() throws Exception {
+        final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
         final EntitlementDao dao = Mockito.mock(EntitlementDao.class);
         final CatalogService catalogService = new MockCatalogService(new MockCatalog());
         final SubscriptionApiService apiService =  Mockito.mock(SubscriptionApiService.class);
         final EntitlementTimelineApi timelineApi = Mockito.mock(EntitlementTimelineApi.class);
-        final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(Mockito.mock(IDBI.class), clock);
+        final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(clock, nonEntityDao, new CacheControllerDispatcher());
         transferApi = new DefaultEntitlementTransferApi(clock, dao, timelineApi, catalogService, apiService, internalCallContextFactory);
     }
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
index 228e23f..bc9123f 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
@@ -20,6 +20,8 @@ import org.skife.jdbi.v2.IDBI;
 
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.notificationq.NotificationQueueService;
@@ -29,7 +31,7 @@ import com.google.inject.Inject;
 public class MockEntitlementDaoSql extends DefaultEntitlementDao {
     @Inject
     public MockEntitlementDaoSql(final IDBI dbi, final Clock clock, final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
-                                 final InternalBus eventBus, final CatalogService catalogService) {
-        super(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService);
+                                 final InternalBus eventBus, final CatalogService catalogService, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+        super(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService, cacheControllerDispatcher, nonEntityDao);
     }
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
index dd48560..c45dae5 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
@@ -21,7 +21,9 @@ import org.mockito.Mockito;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.catalog.glue.CatalogModule;
 import com.ning.billing.mock.glue.MockClockModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 
 public class MockEngineModule extends DefaultEntitlementModule {
     @Override
@@ -31,5 +33,6 @@ public class MockEngineModule extends DefaultEntitlementModule {
         bind(AccountUserApi.class).toInstance(Mockito.mock(AccountUserApi.class));
         install(new MockClockModule());
         install(new CallContextModule());
+        install(new CacheModule());
     }
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleMemory.java
index a580f01..63e0a44 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleMemory.java
@@ -16,16 +16,22 @@
 
 package com.ning.billing.entitlement.glue;
 
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
 import org.mockito.Mockito;
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.jdbi.v2.IDBI;
 
+import com.ning.billing.ObjectType;
 import com.ning.billing.entitlement.api.timeline.RepairEntitlementLifecycleDao;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.engine.dao.MockEntitlementDaoMemory;
 import com.ning.billing.entitlement.engine.dao.RepairEntitlementDao;
-import com.ning.billing.util.callcontext.CallContextSqlDao;
-import com.ning.billing.util.callcontext.MockCallContextSqlDao;
+import com.ning.billing.mock.glue.MockNonEntityDaoModule;
+import com.ning.billing.util.cache.CacheController;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.glue.BusModule;
 import com.ning.billing.util.glue.BusModule.BusType;
 import com.ning.billing.util.notificationq.MockNotificationQueueService;
@@ -56,7 +62,6 @@ public class MockEngineModuleMemory extends MockEngineModule {
 
     protected void installDBI() {
         final IDBI idbi = Mockito.mock(IDBI.class);
-        Mockito.when(idbi.onDemand(CallContextSqlDao.class)).thenReturn(new MockCallContextSqlDao());
         bind(IDBI.class).toInstance(idbi);
     }
 
@@ -66,5 +71,7 @@ public class MockEngineModuleMemory extends MockEngineModule {
         super.configure();
         install(new BusModule(BusType.MEMORY));
         installNotificationQueue();
+
+        install(new MockNonEntityDaoModule());
     }
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
index 922fa16..d66a7aa 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
@@ -30,6 +30,7 @@ import com.ning.billing.entitlement.engine.dao.RepairEntitlementDao;
 import com.ning.billing.util.glue.BusModule;
 import com.ning.billing.util.glue.BusModule.BusType;
 import com.ning.billing.util.glue.CustomFieldModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 
 import com.google.inject.name.Names;
@@ -57,6 +58,7 @@ public class MockEngineModuleSql extends MockEngineModule {
 
     @Override
     protected void configure() {
+        install(new NonEntityDaoModule());
         installDBI();
         install(new NotificationQueueModule());
         install(new CustomFieldModule());
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index 961ced2..30512d3 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -41,8 +41,11 @@ import com.ning.billing.invoice.api.InvoicePayment.InvoicePaymentType;
 import com.ning.billing.invoice.api.user.DefaultInvoiceAdjustmentEvent;
 import com.ning.billing.invoice.model.InvoiceItemList;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.entity.dao.EntityDaoBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
@@ -70,8 +73,11 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     @Inject
     public DefaultInvoiceDao(final IDBI dbi,
                              final NextBillingDatePoster nextBillingDatePoster,
-                             final InternalBus eventBus) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi), InvoiceSqlDao.class);
+                             final InternalBus eventBus,
+                             final Clock clock,
+                             final CacheControllerDispatcher cacheControllerDispatcher,
+                             final NonEntityDao nonEntityDao) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), InvoiceSqlDao.class);
         this.nextBillingDatePoster = nextBillingDatePoster;
         this.eventBus = eventBus;
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemModelDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemModelDao.java
index 6f289c7..6f99488 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemModelDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemModelDao.java
@@ -234,4 +234,9 @@ public class InvoiceItemModelDao extends EntityBase implements EntityModelDao<In
     public TableName getTableName() {
         return TableName.INVOICE_ITEMS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceModelDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceModelDao.java
index f28a0ea..6feb2c9 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceModelDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceModelDao.java
@@ -176,4 +176,10 @@ public class InvoiceModelDao extends EntityBase implements EntityModelDao<Invoic
     public TableName getTableName() {
         return TableName.INVOICES;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
+
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentModelDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentModelDao.java
index b3462bc..ff8eadc 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentModelDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentModelDao.java
@@ -169,4 +169,9 @@ public class InvoicePaymentModelDao extends EntityBase implements EntityModelDao
     public TableName getTableName() {
         return TableName.INVOICE_PAYMENTS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/invoice/TestDefaultInvoicePaymentApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/invoice/TestDefaultInvoicePaymentApi.java
index cbb693d..6cfe4cb 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/invoice/TestDefaultInvoicePaymentApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/invoice/TestDefaultInvoicePaymentApi.java
@@ -43,9 +43,12 @@ import com.ning.billing.invoice.dao.InvoiceItemSqlDao;
 import com.ning.billing.invoice.dao.InvoiceSqlDao;
 import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.svcapi.invoice.InvoiceInternalApi;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 
@@ -61,6 +64,7 @@ public class TestDefaultInvoicePaymentApi extends InvoiceTestSuiteWithEmbeddedDB
     private static final Currency CURRENCY = Currency.EUR;
 
     private final Clock clock = new ClockMock();
+    private final CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
 
     private InvoiceSqlDao invoiceSqlDao;
     private InvoiceItemSqlDao invoiceItemSqlDao;
@@ -78,9 +82,10 @@ public class TestDefaultInvoicePaymentApi extends InvoiceTestSuiteWithEmbeddedDB
         invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
         invoiceItemSqlDao.test(internalCallContext);
 
+        final NonEntityDao nonEntityDao = new DefaultNonEntityDao(dbi);
         final NextBillingDatePoster nextBillingDatePoster = new MockNextBillingDatePoster();
-        internalCallContextFactory = new InternalCallContextFactory(dbi, clock);
-        final InvoiceDao invoiceDao = new DefaultInvoiceDao(dbi, nextBillingDatePoster, Mockito.mock(InternalBus.class));
+        internalCallContextFactory = new InternalCallContextFactory(clock, nonEntityDao, controllerDispatcher);
+        final InvoiceDao invoiceDao = new DefaultInvoiceDao(dbi, nextBillingDatePoster, Mockito.mock(InternalBus.class), clock, controllerDispatcher, nonEntityDao);
         invoicePaymentApi = new DefaultInvoicePaymentApi(invoiceDao, internalCallContextFactory);
         invoiceInternalApi = new DefaultInvoiceInternalApi(invoiceDao);
     }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
index 3266965..8286665 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
@@ -26,6 +26,7 @@ import com.ning.billing.invoice.notification.NextBillingDateNotifier;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
 import com.ning.billing.invoice.notification.NullInvoiceNotifier;
 import com.ning.billing.util.email.templates.TemplateModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.template.translation.TranslatorConfig;
 
 public class MockModuleNoEntitlement extends MockModule {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
index 7559994..6bfe42d 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
@@ -39,10 +39,12 @@ import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
 import com.ning.billing.invoice.tests.InvoicingTestBase;
 import com.ning.billing.util.bus.InMemoryInternalBus;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.InvoiceConfig;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 
@@ -63,6 +65,8 @@ public class InvoiceDaoTestBase extends InvoicingTestBase {
     protected Clock clock;
     protected InvoiceGenerator generator;
     protected InternalBus bus;
+    protected CacheControllerDispatcher controllerDispatcher;
+
 
     private final InvoiceConfig invoiceConfig = new InvoiceConfig() {
         @Override
@@ -99,7 +103,9 @@ public class InvoiceDaoTestBase extends InvoicingTestBase {
         bus.start();
 
         final NextBillingDatePoster nextBillingDatePoster = new MockNextBillingDatePoster();
-        invoiceDao = new DefaultInvoiceDao(dbi, nextBillingDatePoster, bus);
+        controllerDispatcher = new CacheControllerDispatcher();
+
+        invoiceDao = new DefaultInvoiceDao(dbi, nextBillingDatePoster, bus, clock, controllerDispatcher, new DefaultNonEntityDao(dbi));
         invoiceDao.test(internalCallContext);
 
         invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/TestDefaultInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/TestDefaultInvoiceDao.java
index e3bb748..16b0c48 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/TestDefaultInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/TestDefaultInvoiceDao.java
@@ -30,10 +30,12 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.ning.billing.ErrorCode;
+import com.ning.billing.dao.MockNonEntityDao;
 import com.ning.billing.invoice.InvoiceTestSuite;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
@@ -44,6 +46,8 @@ public class TestDefaultInvoiceDao extends InvoiceTestSuite {
 
     private InvoiceSqlDao invoiceSqlDao;
     private DefaultInvoiceDao dao;
+    private final CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
+
 
     @BeforeMethod(groups = "fast")
     public void setUp() throws Exception {
@@ -65,7 +69,7 @@ public class TestDefaultInvoiceDao extends InvoiceTestSuite {
         });
 
         final NextBillingDatePoster poster = Mockito.mock(NextBillingDatePoster.class);
-        dao = new DefaultInvoiceDao(idbi, poster, Mockito.mock(InternalBus.class));
+        dao = new DefaultInvoiceDao(idbi, poster, Mockito.mock(InternalBus.class), clock, controllerDispatcher, new MockNonEntityDao());
     }
 
     @Test(groups = "fast")
diff --git a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
index 65b6571..d63a881 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
@@ -42,7 +42,9 @@ import com.ning.billing.util.email.EmailModule;
 import com.ning.billing.util.email.templates.TemplateModule;
 import com.ning.billing.util.globallocker.TestGlobalLockerModule;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CustomFieldModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
@@ -64,6 +66,8 @@ public class MockModule extends AbstractModule {
         bind(CallContextFactory.class).to(DefaultCallContextFactory.class).asEagerSingleton();
         install(new TagStoreModule());
         install(new CustomFieldModule());
+        install(new CacheModule());
+        install(new NonEntityDaoModule());
 
         final DBTestingHelper helper = KillbillTestSuiteWithEmbeddedDB.getDBTestingHelper();
         if (helper.isUsingLocalInstance()) {
@@ -75,9 +79,10 @@ public class MockModule extends AbstractModule {
             bind(IDBI.class).toInstance(dbi);
         }
 
-        final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(helper.getDBI(), clock);
+        /*
+        final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(helper.getDBI(), clock, nonEntityDao);
         bind(InternalCallContextFactory.class).toInstance(internalCallContextFactory);
-
+*/
         bind(InvoiceFormatterFactory.class).to(DefaultInvoiceFormatterFactory.class).asEagerSingleton();
 
         bind(AccountInternalApi.class).toInstance(Mockito.mock(AccountInternalApi.class));
diff --git a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
index 15d08b6..3d5cc76 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
@@ -45,11 +45,13 @@ import com.ning.billing.invoice.glue.InvoiceModuleWithMocks;
 import com.ning.billing.invoice.template.formatters.DefaultInvoiceFormatterFactory;
 import com.ning.billing.lifecycle.KillbillService;
 import com.ning.billing.mock.glue.MockJunctionModule;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.InvoiceConfig;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.email.templates.TemplateModule;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -57,6 +59,8 @@ import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
 import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 import com.ning.billing.util.glue.BusModule;
 import com.ning.billing.util.glue.BusModule.BusType;
+import com.ning.billing.util.glue.CacheModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.notificationq.NotificationQueueService;
@@ -81,6 +85,8 @@ public class TestNextBillingDateNotifier extends InvoiceTestSuiteWithEmbeddedDB 
     private NotificationQueueService notificationQueueService;
     private InternalCallContextFactory internalCallContextFactory;
     private EntitySqlDaoTransactionalJdbiWrapper entitySqlDaoTransactionalJdbiWrapper;
+    private CacheControllerDispatcher controllerDispatcher;
+    private NonEntityDao nonEntityDao;
 
     private static final class InvoiceListenerMock extends InvoiceListener {
 
@@ -125,6 +131,8 @@ public class TestNextBillingDateNotifier extends InvoiceTestSuiteWithEmbeddedDB 
                 install(new NotificationQueueModule());
                 install(new TemplateModule());
                 install(new TagStoreModule());
+                install(new CacheModule());
+                install(new NonEntityDaoModule());
 
                 final DBTestingHelper helper = KillbillTestSuiteWithEmbeddedDB.getDBTestingHelper();
                 if (helper.isUsingLocalInstance()) {
@@ -136,9 +144,10 @@ public class TestNextBillingDateNotifier extends InvoiceTestSuiteWithEmbeddedDB 
                     bind(IDBI.class).toInstance(dbi);
                 }
 
-                final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(helper.getDBI(), clock);
+                /*
+                final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(helper.getDBI(), clock, nonEntityDao);
                 bind(InternalCallContextFactory.class).toInstance(internalCallContextFactory);
-
+*/
                 bind(InvoiceFormatterFactory.class).to(DefaultInvoiceFormatterFactory.class).asEagerSingleton();
 
                 bind(AccountInternalApi.class).toInstance(Mockito.mock(AccountInternalApi.class));
@@ -149,7 +158,10 @@ public class TestNextBillingDateNotifier extends InvoiceTestSuiteWithEmbeddedDB 
         clock = g.getInstance(Clock.class);
         final IDBI dbi = g.getInstance(IDBI.class);
 
-        entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi);
+        nonEntityDao = g.getInstance(NonEntityDao.class);
+        controllerDispatcher = g.getInstance(CacheControllerDispatcher.class);
+
+        entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao);
 
         eventBus = g.getInstance(InternalBus.class);
         notificationQueueService = g.getInstance(NotificationQueueService.class);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java b/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
index 8e701dd..bd980a0 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
@@ -44,9 +44,12 @@ import com.ning.billing.invoice.dao.InvoiceSqlDao;
 import com.ning.billing.invoice.glue.InvoiceModuleWithEmbeddedDb;
 import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.svcapi.invoice.InvoiceInternalApi;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 
@@ -69,6 +72,8 @@ public class TestChargeBacks extends InvoiceTestSuiteWithEmbeddedDB {
     private InternalCallContextFactory internalCallContextFactory;
 
     private final Clock clock = new ClockMock();
+    private final CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
+
     private static final Currency CURRENCY = Currency.EUR;
 
     @BeforeSuite(groups = "slow")
@@ -80,11 +85,12 @@ public class TestChargeBacks extends InvoiceTestSuiteWithEmbeddedDB {
         invoiceSqlDao = dbi.onDemand(InvoiceSqlDao.class);
         invoiceSqlDao.test(internalCallContext);
 
+        final NonEntityDao nonEntityDao = new DefaultNonEntityDao(dbi);
         invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
         invoiceItemSqlDao.test(internalCallContext);
         final NextBillingDatePoster nextBillingDatePoster = new MockNextBillingDatePoster();
-        internalCallContextFactory = new InternalCallContextFactory(dbi, clock);
-        final InvoiceDao invoiceDao = new DefaultInvoiceDao(dbi, nextBillingDatePoster, Mockito.mock(InternalBus.class));
+        internalCallContextFactory = new InternalCallContextFactory(clock, nonEntityDao, controllerDispatcher);
+        final InvoiceDao invoiceDao = new DefaultInvoiceDao(dbi, nextBillingDatePoster, Mockito.mock(InternalBus.class), clock, controllerDispatcher, nonEntityDao);
         invoicePaymentApi = new DefaultInvoicePaymentApi(invoiceDao, internalCallContextFactory);
         invoiceApi = new DefaultInvoiceInternalApi(invoiceDao);
     }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
index 952bf60..42ac6a1 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -178,7 +178,7 @@ public class InvoiceResource extends JaxRsResourceBase {
 
         final Account account = accountApi.getAccountById(UUID.fromString(accountId), callContext);
 
-        final DateTime inputDateTime = DATE_TIME_FORMATTER.parseDateTime(targetDateTime);
+        final DateTime inputDateTime =  targetDateTime != null ? DATE_TIME_FORMATTER.parseDateTime(targetDateTime) : clock.getUTCNow();
         final LocalDate inputDate = inputDateTime.toDateTime(account.getTimeZone()).toLocalDate();
 
         final Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, dryRun,
diff --git a/junction/src/main/java/com/ning/billing/junction/dao/BlockingStateModelDao.java b/junction/src/main/java/com/ning/billing/junction/dao/BlockingStateModelDao.java
index 5dbdd25..a1c7bfc 100644
--- a/junction/src/main/java/com/ning/billing/junction/dao/BlockingStateModelDao.java
+++ b/junction/src/main/java/com/ning/billing/junction/dao/BlockingStateModelDao.java
@@ -98,6 +98,11 @@ public class BlockingStateModelDao extends EntityBase implements EntityModelDao<
     }
 
     @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
+
+    @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("BlockingStateModelDao");
diff --git a/junction/src/main/java/com/ning/billing/junction/dao/DefaultBlockingStateDao.java b/junction/src/main/java/com/ning/billing/junction/dao/DefaultBlockingStateDao.java
index 1ea8e5a..8ed806f 100644
--- a/junction/src/main/java/com/ning/billing/junction/dao/DefaultBlockingStateDao.java
+++ b/junction/src/main/java/com/ning/billing/junction/dao/DefaultBlockingStateDao.java
@@ -27,9 +27,11 @@ import org.skife.jdbi.v2.IDBI;
 
 import com.ning.billing.junction.api.Blockable;
 import com.ning.billing.junction.api.BlockingState;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
@@ -43,8 +45,8 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
     private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
 
     @Inject
-    public DefaultBlockingStateDao(final IDBI dbi) {
-        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi);
+    public DefaultBlockingStateDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
     }
 
     @Override
diff --git a/junction/src/test/java/com/ning/billing/junction/api/blocking/TestDefaultBlockingApi.java b/junction/src/test/java/com/ning/billing/junction/api/blocking/TestDefaultBlockingApi.java
index eeb92dc..8758d44 100644
--- a/junction/src/test/java/com/ning/billing/junction/api/blocking/TestDefaultBlockingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/api/blocking/TestDefaultBlockingApi.java
@@ -32,18 +32,23 @@ import com.ning.billing.junction.api.svcs.DefaultInternalBlockingApi;
 import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.junction.dao.BlockingStateDao;
 import com.ning.billing.junction.dao.DefaultBlockingStateDao;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
 import com.ning.billing.util.svcapi.junction.DefaultBlockingState;
 
 public class TestDefaultBlockingApi extends JunctionTestSuiteWithEmbeddedDB {
 
     private final ClockMock clock = new ClockMock();
+    private final CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
+
 
     private DefaultInternalBlockingApi blockingApi;
 
+
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
-        final BlockingStateDao blockingStateDao = new DefaultBlockingStateDao(getDBI());
+        final BlockingStateDao blockingStateDao = new DefaultBlockingStateDao(getDBI(), clock, controllerDispatcher, new DefaultNonEntityDao(getDBI()));
         blockingApi = new DefaultInternalBlockingApi(blockingStateDao, clock);
     }
 
diff --git a/junction/src/test/java/com/ning/billing/junction/MockModule.java b/junction/src/test/java/com/ning/billing/junction/MockModule.java
index 7865bcd..7d2ae94 100644
--- a/junction/src/test/java/com/ning/billing/junction/MockModule.java
+++ b/junction/src/test/java/com/ning/billing/junction/MockModule.java
@@ -20,7 +20,9 @@ import com.ning.billing.catalog.glue.CatalogModule;
 import com.ning.billing.junction.glue.DefaultJunctionModule;
 import com.ning.billing.mock.glue.MockClockModule;
 import com.ning.billing.mock.glue.MockDbHelperModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 
 public class MockModule extends DefaultJunctionModule {
     @Override
@@ -31,6 +33,8 @@ public class MockModule extends DefaultJunctionModule {
         install(new MockDbHelperModule());
         install(new CallContextModule());
         install(new CatalogModule());
+        install(new CacheModule());
+        install(new NonEntityDaoModule());
     }
 
     @Override
diff --git a/meter/src/test/java/com/ning/billing/meter/timeline/aggregator/TestTimelineAggregator.java b/meter/src/test/java/com/ning/billing/meter/timeline/aggregator/TestTimelineAggregator.java
index 716a4e3..acb9341 100644
--- a/meter/src/test/java/com/ning/billing/meter/timeline/aggregator/TestTimelineAggregator.java
+++ b/meter/src/test/java/com/ning/billing/meter/timeline/aggregator/TestTimelineAggregator.java
@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicLong;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.mockito.Mockito;
 import org.skife.config.ConfigurationObjectFactory;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
@@ -42,9 +43,11 @@ import com.ning.billing.meter.timeline.samples.ScalarSample;
 import com.ning.billing.meter.timeline.sources.SourceSamplesForTimestamp;
 import com.ning.billing.meter.timeline.times.DefaultTimelineCoder;
 import com.ning.billing.meter.timeline.times.TimelineCoder;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.MeterConfig;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -61,7 +64,8 @@ public class TestTimelineAggregator extends MeterTestSuiteWithEmbeddedDB {
     private static final TimelineCoder timelineCoder = new DefaultTimelineCoder();
     private static final SampleCoder sampleCoder = new DefaultSampleCoder();
 
-    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(getDBI(), new ClockMock());
+    private final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
+    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(new ClockMock(), nonEntityDao, new CacheControllerDispatcher());
 
     private TimelineDao timelineDao;
     private TimelineAggregator aggregator;
diff --git a/meter/src/test/java/com/ning/billing/meter/timeline/persistent/TestFileBackedBuffer.java b/meter/src/test/java/com/ning/billing/meter/timeline/persistent/TestFileBackedBuffer.java
index b41aec0..d6a789c 100644
--- a/meter/src/test/java/com/ning/billing/meter/timeline/persistent/TestFileBackedBuffer.java
+++ b/meter/src/test/java/com/ning/billing/meter/timeline/persistent/TestFileBackedBuffer.java
@@ -44,9 +44,11 @@ import com.ning.billing.meter.timeline.codec.SampleCoder;
 import com.ning.billing.meter.timeline.sources.SourceSamplesForTimestamp;
 import com.ning.billing.meter.timeline.times.DefaultTimelineCoder;
 import com.ning.billing.meter.timeline.times.TimelineCoder;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.MeterConfig;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.collect.ImmutableMap;
 
@@ -64,7 +66,8 @@ public class TestFileBackedBuffer extends MeterTestSuite {
     private static final TimelineCoder timelineCoder = new DefaultTimelineCoder();
     private static final SampleCoder sampleCoder = new DefaultSampleCoder();
 
-    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(Mockito.mock(DBI.class), new ClockMock());
+    private final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
+    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(new ClockMock(), nonEntityDao, new CacheControllerDispatcher());
     private final TimelineDao dao = new MockTimelineDao();
     private TimelineEventHandler timelineEventHandler;
 
diff --git a/meter/src/test/java/com/ning/billing/meter/timeline/persistent/TestSamplesReplayer.java b/meter/src/test/java/com/ning/billing/meter/timeline/persistent/TestSamplesReplayer.java
index 4da4131..75016d1 100644
--- a/meter/src/test/java/com/ning/billing/meter/timeline/persistent/TestSamplesReplayer.java
+++ b/meter/src/test/java/com/ning/billing/meter/timeline/persistent/TestSamplesReplayer.java
@@ -40,8 +40,11 @@ import com.ning.billing.meter.timeline.samples.ScalarSample;
 import com.ning.billing.meter.timeline.sources.SourceSamplesForTimestamp;
 import com.ning.billing.meter.timeline.times.DefaultTimelineCoder;
 import com.ning.billing.meter.timeline.times.TimelineCoder;
+import com.ning.billing.util.cache.CacheController;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.collect.ImmutableMap;
 
@@ -58,7 +61,8 @@ public class TestSamplesReplayer extends MeterTestSuite {
     private static final TimelineCoder timelineCoder = new DefaultTimelineCoder();
     private static final SampleCoder sampleCoder = new DefaultSampleCoder();
 
-    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(Mockito.mock(DBI.class), new ClockMock());
+    private final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
+    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(new ClockMock(), nonEntityDao, new CacheControllerDispatcher());
 
     @BeforeMethod(groups = "fast")
     public void setUp() throws Exception {
diff --git a/meter/src/test/java/com/ning/billing/meter/timeline/TestInMemoryEventHandler.java b/meter/src/test/java/com/ning/billing/meter/timeline/TestInMemoryEventHandler.java
index 2ee5851..ddd884d 100644
--- a/meter/src/test/java/com/ning/billing/meter/timeline/TestInMemoryEventHandler.java
+++ b/meter/src/test/java/com/ning/billing/meter/timeline/TestInMemoryEventHandler.java
@@ -36,9 +36,11 @@ import com.ning.billing.meter.timeline.persistent.FileBackedBuffer;
 import com.ning.billing.meter.timeline.persistent.TimelineDao;
 import com.ning.billing.meter.timeline.times.DefaultTimelineCoder;
 import com.ning.billing.meter.timeline.times.TimelineCoder;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.MeterConfig;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.collect.ImmutableMap;
 
@@ -54,7 +56,9 @@ public class TestInMemoryEventHandler extends MeterTestSuite {
     private static final TimelineCoder timelineCoder = new DefaultTimelineCoder();
     private static final SampleCoder sampleCoder = new DefaultSampleCoder();
 
-    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(Mockito.mock(DBI.class), new ClockMock());
+    private final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
+    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(new ClockMock(), nonEntityDao, new CacheControllerDispatcher());
+
 
     private final TimelineDao dao = new MockTimelineDao();
     private TimelineEventHandler timelineEventHandler;
diff --git a/meter/src/test/java/com/ning/billing/meter/timeline/TestTimelineEventHandler.java b/meter/src/test/java/com/ning/billing/meter/timeline/TestTimelineEventHandler.java
index 89d5512..4ac3c31 100644
--- a/meter/src/test/java/com/ning/billing/meter/timeline/TestTimelineEventHandler.java
+++ b/meter/src/test/java/com/ning/billing/meter/timeline/TestTimelineEventHandler.java
@@ -36,9 +36,11 @@ import com.ning.billing.meter.timeline.samples.ScalarSample;
 import com.ning.billing.meter.timeline.sources.SourceSamplesForTimestamp;
 import com.ning.billing.meter.timeline.times.DefaultTimelineCoder;
 import com.ning.billing.meter.timeline.times.TimelineCoder;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.MeterConfig;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.collect.ImmutableMap;
 
@@ -49,7 +51,8 @@ public class TestTimelineEventHandler extends MeterTestSuite {
     private static final TimelineCoder timelineCoder = new DefaultTimelineCoder();
     private static final SampleCoder sampleCoder = new DefaultSampleCoder();
 
-    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(Mockito.mock(DBI.class), new ClockMock());
+    private final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
+    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(new ClockMock(), nonEntityDao, new CacheControllerDispatcher());
 
     private final TimelineDao dao = new MockTimelineDao();
 
diff --git a/meter/src/test/java/com/ning/billing/meter/timeline/TestTimelineSourceEventAccumulator.java b/meter/src/test/java/com/ning/billing/meter/timeline/TestTimelineSourceEventAccumulator.java
index 55dd0b8..d676171 100644
--- a/meter/src/test/java/com/ning/billing/meter/timeline/TestTimelineSourceEventAccumulator.java
+++ b/meter/src/test/java/com/ning/billing/meter/timeline/TestTimelineSourceEventAccumulator.java
@@ -35,8 +35,10 @@ import com.ning.billing.meter.timeline.samples.ScalarSample;
 import com.ning.billing.meter.timeline.sources.SourceSamplesForTimestamp;
 import com.ning.billing.meter.timeline.times.DefaultTimelineCoder;
 import com.ning.billing.meter.timeline.times.TimelineCoder;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.NonEntityDao;
 
 public class TestTimelineSourceEventAccumulator extends MeterTestSuite {
 
@@ -47,7 +49,8 @@ public class TestTimelineSourceEventAccumulator extends MeterTestSuite {
     private static final TimelineCoder timelineCoder = new DefaultTimelineCoder();
     private static final SampleCoder sampleCoder = new DefaultSampleCoder();
 
-    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(Mockito.mock(DBI.class), new ClockMock());
+    private final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
+    private final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(new ClockMock(), nonEntityDao, new CacheControllerDispatcher());
 
     @Test(groups = "fast")
     public void testSimpleAggregate() throws IOException {
diff --git a/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java b/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
index 4e283e1..7b21af7 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
@@ -49,6 +49,7 @@ import com.ning.billing.overdue.OverdueProperties;
 import com.ning.billing.overdue.OverdueTestSuiteWithEmbeddedDB;
 import com.ning.billing.overdue.glue.DefaultOverdueModule;
 import com.ning.billing.overdue.listener.OverdueListener;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.CallContextFactory;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
@@ -59,11 +60,15 @@ import com.ning.billing.util.config.CatalogConfig;
 import com.ning.billing.util.config.InvoiceConfig;
 import com.ning.billing.util.customfield.dao.CustomFieldDao;
 import com.ning.billing.util.customfield.dao.DefaultCustomFieldDao;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.email.EmailModule;
 import com.ning.billing.util.email.templates.TemplateModule;
 import com.ning.billing.util.globallocker.GlobalLocker;
 import com.ning.billing.util.globallocker.MySqlGlobalLocker;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CacheModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.notificationq.NotificationQueueService;
@@ -95,7 +100,7 @@ public class TestOverdueCheckNotifier extends OverdueTestSuiteWithEmbeddedDB {
         UUID latestSubscriptionId = null;
 
         public OverdueListenerMock() {
-            super(null, new InternalCallContextFactory(getDBI(), new ClockMock()));
+            super(null, new InternalCallContextFactory(new ClockMock(), new DefaultNonEntityDao(getDBI()), new CacheControllerDispatcher()));
         }
 
         @Override
@@ -136,6 +141,8 @@ public class TestOverdueCheckNotifier extends OverdueTestSuiteWithEmbeddedDB {
                 install(new EmailModule());
                 install(new TemplateModule());
                 install(new NotificationQueueModule());
+                install(new CacheModule());
+                install(new NonEntityDaoModule());
                 final AccountInternalApi accountApi = Mockito.mock(AccountInternalApi.class);
                 bind(AccountInternalApi.class).toInstance(accountApi);
 
diff --git a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestBase.java b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestBase.java
index e6a3a8e..936c074 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestBase.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestBase.java
@@ -58,7 +58,9 @@ import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.email.EmailModule;
 import com.ning.billing.util.email.templates.TemplateModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
@@ -72,7 +74,8 @@ import com.google.inject.Inject;
 
 @Guice(modules = {DefaultOverdueModule.class, OverdueListenerTesterModule.class, MockClockModule.class, ApplicatorMockJunctionModule.class,
                   CallContextModule.class, CatalogModule.class, MockInvoiceModule.class, MockPaymentModule.class, NotificationQueueModule.class,
-                  EmailModule.class, TemplateModule.class, TestDbiModule.class, TagStoreModule.class, MockEntitlementModule.class, MockInvoiceModule.class, MockAccountModule.class})
+                  EmailModule.class, TemplateModule.class, TestDbiModule.class, MockEntitlementModule.class, MockInvoiceModule.class,
+        MockAccountModule.class, CacheModule.class, NonEntityDaoModule.class, TagStoreModule.class})
 public abstract class OverdueTestBase extends OverdueTestSuiteWithEmbeddedDB {
     protected final String configXml =
             "<overdueConfig>" +
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
index 381fd3b..8456706 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
@@ -27,8 +27,11 @@ import org.skife.jdbi.v2.IDBI;
 
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -41,8 +44,8 @@ public class DefaultPaymentDao implements PaymentDao {
     private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
 
     @Inject
-    public DefaultPaymentDao(final IDBI dbi) {
-        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi);
+    public DefaultPaymentDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
     }
 
     @Override
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
index 5defd47..63aaaa6 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
@@ -178,4 +178,10 @@ public class PaymentAttemptModelDao extends EntityBase implements EntityModelDao
     public TableName getTableName() {
         return TableName.PAYMENT_ATTEMPTS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.PAYMENT_ATTEMPT_HISTORY;
+    }
+
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodModelDao.java
index 9f3fc4f..9287a57 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodModelDao.java
@@ -128,4 +128,10 @@ public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<
     public TableName getTableName() {
         return TableName.PAYMENT_METHODS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.PAYMENT_METHOD_HISTORY;
+    }
+
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
index ab6d409..4d409c1 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
@@ -205,4 +205,10 @@ public class PaymentModelDao extends EntityBase implements EntityModelDao<Paymen
     public TableName getTableName() {
         return TableName.PAYMENTS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.PAYMENT_HISTORY;
+    }
+
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java
index 22c90eb..b861511 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java
@@ -165,4 +165,10 @@ public class RefundModelDao extends EntityBase implements EntityModelDao<Refund>
     public TableName getTableName() {
         return TableName.REFUNDS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.REFUND_HISTORY;
+    }
+
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 8224949..27c1399 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -37,6 +37,7 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.mock.glue.MockClockModule;
 import com.ning.billing.mock.glue.MockJunctionModule;
+import com.ning.billing.mock.glue.MockNonEntityDaoModule;
 import com.ning.billing.payment.MockRecurringInvoiceItem;
 import com.ning.billing.payment.PaymentTestSuite;
 import com.ning.billing.payment.TestHelper;
@@ -44,7 +45,9 @@ import com.ning.billing.payment.api.Payment.PaymentAttempt;
 import com.ning.billing.payment.glue.PaymentTestModuleWithMocks;
 import com.ning.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.svcsapi.bus.InternalBus.EventBusException;
@@ -56,7 +59,7 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
-@Guice(modules = {PaymentTestModuleWithMocks.class, MockClockModule.class, MockJunctionModule.class, CallContextModule.class})
+@Guice(modules = {PaymentTestModuleWithMocks.class, MockClockModule.class, MockJunctionModule.class, CacheModule.class, MockNonEntityDaoModule.class, CallContextModule.class})
 public class TestPaymentApi extends PaymentTestSuite {
     private static final Logger log = LoggerFactory.getLogger(TestPaymentApi.class);
 
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index bf50c4c..a55e42b 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -36,8 +36,10 @@ import com.ning.billing.dbi.DbiConfig;
 import com.ning.billing.payment.PaymentTestSuiteWithEmbeddedDB;
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.DefaultClock;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
@@ -50,12 +52,15 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
     private DBTestingHelper helper;
     private IDBI dbi;
     private Clock clock;
+    private CacheControllerDispatcher controllerDispatcher;
+
 
     @BeforeSuite(groups = "slow")
     public void setup() throws IOException {
         clock = new DefaultClock();
+        controllerDispatcher = new CacheControllerDispatcher();
         setupDb();
-        paymentDao = new DefaultPaymentDao(dbi);
+        paymentDao = new DefaultPaymentDao(dbi, clock, controllerDispatcher, new DefaultNonEntityDao(dbi));
     }
 
     private void setupDb() {
diff --git a/payment/src/test/java/com/ning/billing/payment/glue/PaymentTestModuleWithMocks.java b/payment/src/test/java/com/ning/billing/payment/glue/PaymentTestModuleWithMocks.java
index 0da7d2b..2bc60f0 100644
--- a/payment/src/test/java/com/ning/billing/payment/glue/PaymentTestModuleWithMocks.java
+++ b/payment/src/test/java/com/ning/billing/payment/glue/PaymentTestModuleWithMocks.java
@@ -31,9 +31,7 @@ import com.ning.billing.mock.glue.MockNotificationQueueModule;
 import com.ning.billing.payment.dao.MockPaymentDao;
 import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
-import com.ning.billing.util.callcontext.CallContextSqlDao;
 import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.callcontext.MockCallContextSqlDao;
 import com.ning.billing.util.config.PaymentConfig;
 import com.ning.billing.util.globallocker.GlobalLocker;
 import com.ning.billing.util.globallocker.MockGlobalLocker;
@@ -71,7 +69,6 @@ public class PaymentTestModuleWithMocks extends PaymentModule {
     @Override
     protected void installPaymentDao() {
         final IDBI idbi = Mockito.mock(IDBI.class);
-        Mockito.when(idbi.onDemand(CallContextSqlDao.class)).thenReturn(new MockCallContextSqlDao());
         bind(IDBI.class).toInstance(idbi);
         bind(PaymentDao.class).to(MockPaymentDao.class).asEagerSingleton();
     }
diff --git a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
index 80d84e5..3ca7eb4 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -32,6 +32,7 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.mock.glue.MockNonEntityDaoModule;
 import com.ning.billing.util.config.PaymentConfig;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.mock.glue.MockClockModule;
@@ -48,7 +49,9 @@ import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
 import com.ning.billing.payment.retry.FailedPaymentRetryService;
 import com.ning.billing.payment.retry.PluginFailureRetryService;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.svcapi.invoice.InvoiceInternalApi;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 
@@ -60,7 +63,7 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
-@Guice(modules = {PaymentTestModuleWithMocks.class, MockClockModule.class, MockJunctionModule.class, CallContextModule.class})
+@Guice(modules = {PaymentTestModuleWithMocks.class, MockClockModule.class, MockJunctionModule.class, CacheModule.class, CallContextModule.class, MockNonEntityDaoModule.class})
 public class TestRetryService extends PaymentTestSuite {
     @Inject
     private PaymentConfig paymentConfig;

pom.xml 8(+8 -0)

diff --git a/pom.xml b/pom.xml
index 0358af0..a5abb2b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,6 +36,7 @@
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <slf4j.version>1.6.5</slf4j.version>
+        <ehcache.version>2.6.2</ehcache.version>
     </properties>
     <modules>
         <module>account</module>
@@ -58,6 +59,12 @@
     <dependencyManagement>
         <dependencies>
             <dependency>
+                <groupId>net.sf.ehcache</groupId>
+                <artifactId>ehcache-core</artifactId>
+                <version>${ehcache.version}</version>
+                <type>jar</type>
+            </dependency>
+            <dependency>
                 <groupId>javax.ws.rs</groupId>
                 <artifactId>jsr311-api</artifactId>
                 <version>1.1.1</version>
@@ -494,6 +501,7 @@
                                 <!-- For some reason, useIdeaDefaultExcludes 
                                     doesn't pick up .idea directory -->
                                 <exclude>.idea/**</exclude>
+                                <exclude>**/*.iml</exclude>
                                 <exclude>**/.project</exclude>
                                 <exclude>.git/**</exclude>
                                 <exclude>.gitignore</exclude>
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
index 15c9b9a..bbb7d5f 100644
--- a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
@@ -16,6 +16,9 @@
 
 package com.ning.billing.server.listeners;
 
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServer;
 import javax.servlet.ServletContextEvent;
 
 import org.slf4j.Logger;
@@ -36,6 +39,8 @@ import com.ning.jetty.core.listeners.SetupServer;
 
 import com.google.inject.Injector;
 import com.google.inject.Module;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.management.ManagementService;
 
 public class KillbillGuiceListener extends SetupServer {
 
@@ -50,6 +55,13 @@ public class KillbillGuiceListener extends SetupServer {
         return new KillbillServerModule();
     }
 
+    private void registerMBeansForCache(final CacheManager cacheManager) {
+        if (cacheManager != null) {
+            final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+            ManagementService.registerMBeans(cacheManager, mBeanServer, false, true, true, true);
+        }
+    }
+
     @Override
     public void contextInitialized(final ServletContextEvent event) {
         final boolean multitenant = Boolean.parseBoolean(System.getProperty(KILLBILL_MULTITENANT_PROPERTY, "false"));
@@ -79,6 +91,8 @@ public class KillbillGuiceListener extends SetupServer {
         killbillBusService = theInjector.getInstance(BusService.class);
         killbilleventHandler = theInjector.getInstance(KillbillEventHandler.class);
 
+        registerMBeansForCache(theInjector.getInstance(CacheManager.class));
+
         /*
                 ObjectMapper mapper = theInjector.getInstance(ObjectMapper.class);
                 mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
index 73e24ba..86779b0 100644
--- a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -49,11 +49,13 @@ import com.ning.billing.util.email.EmailModule;
 import com.ning.billing.util.email.templates.TemplateModule;
 import com.ning.billing.util.glue.AuditModule;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
 import com.ning.billing.util.glue.ClockModule;
 import com.ning.billing.util.glue.CustomFieldModule;
 import com.ning.billing.util.glue.ExportModule;
 import com.ning.billing.util.glue.GlobalLockerModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 
@@ -105,6 +107,7 @@ public class KillbillServerModule extends AbstractModule {
 
     protected void installKillbillModules() {
         install(new EmailModule());
+        install(new CacheModule());
         install(new GlobalLockerModule());
         install(new CustomFieldModule());
         install(new AuditModule());
@@ -125,6 +128,7 @@ public class KillbillServerModule extends AbstractModule {
         install(new ExportModule());
         install(new MeterModule());
         install(new TagStoreModule());
+        install(new NonEntityDaoModule());
         installClock();
     }
 }
diff --git a/server/src/main/resources/ehcache.xml b/server/src/main/resources/ehcache.xml
new file mode 100644
index 0000000..ac86fe3
--- /dev/null
+++ b/server/src/main/resources/ehcache.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Copyright 2010-2012 Ning, Inc.
+  ~
+  ~ Ning licenses this file to you under the Apache License, version 2.0
+  ~ (the "License"); you may not use this file except in compliance with the
+  ~ License.  You may obtain a copy of the License at:
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+  ~ License for the specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="ehcache.xsd" >
+
+  <defaultCache
+      maxElementsInMemory="0"
+      maxElementsOnDisk="0"
+      eternal="false"
+      timeToIdleSeconds="0"
+      timeToLiveSeconds="0"
+      overflowToDisk="false"
+      />
+
+    <cache name="record-id"
+           maxElementsInMemory="100000"
+           maxElementsOnDisk="0"
+           eternal="true"
+           overflowToDisk="false"
+           diskPersistent="false"
+           memoryStoreEvictionPolicy="LFU">
+        <cacheEventListenerFactory
+                class="com.ning.billing.util.cache.ExpirationListenerFactory"
+                properties="" />
+    </cache>
+
+    <cache name="tenant-record-id"
+           maxElementsInMemory="100000"
+           maxElementsOnDisk="0"
+           eternal="true"
+           overflowToDisk="false"
+           diskPersistent="false"
+           memoryStoreEvictionPolicy="LFU">
+        <cacheEventListenerFactory
+                class="com.ning.billing.util.cache.ExpirationListenerFactory"
+                properties="" />
+    </cache>
+
+    <cache name="account-record-id"
+           maxElementsInMemory="100000"
+           maxElementsOnDisk="0"
+           eternal="true"
+           overflowToDisk="false"
+           diskPersistent="false"
+           memoryStoreEvictionPolicy="LFU">
+        <cacheEventListenerFactory
+                class="com.ning.billing.util.cache.ExpirationListenerFactory"
+                properties="" />
+    </cache>
+</ehcache>
+
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
index 715a310..d8dca6b 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -62,9 +62,11 @@ import com.ning.billing.util.email.templates.TemplateModule;
 import com.ning.billing.util.globallocker.TestGlobalLockerModule;
 import com.ning.billing.util.glue.AuditModule;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
 import com.ning.billing.util.glue.CustomFieldModule;
 import com.ning.billing.util.glue.ExportModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.http.client.AsyncHttpClient;
@@ -166,6 +168,8 @@ public class TestJaxrsBase extends KillbillClient {
             Modules.override(new com.ning.billing.payment.setup.PaymentModule()).with(new PaymentMockModule());
             */
             install(new EmailModule());
+            install(new CacheModule());
+            install(new NonEntityDaoModule());
             install(new TestGlobalLockerModule(helper));
             install(new CustomFieldModule());
             install(new TagStoreModule());
diff --git a/server/src/test/java/com/ning/billing/server/security/TestKillbillJdbcRealm.java b/server/src/test/java/com/ning/billing/server/security/TestKillbillJdbcRealm.java
index ed0304b..6cd22b7 100644
--- a/server/src/test/java/com/ning/billing/server/security/TestKillbillJdbcRealm.java
+++ b/server/src/test/java/com/ning/billing/server/security/TestKillbillJdbcRealm.java
@@ -33,6 +33,8 @@ import com.ning.billing.server.ServerTestSuiteWithEmbeddedDB;
 import com.ning.billing.tenant.api.DefaultTenant;
 import com.ning.billing.tenant.dao.DefaultTenantDao;
 import com.ning.billing.tenant.dao.TenantModelDao;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
 
 import com.jolbox.bonecp.BoneCPConfig;
 import com.jolbox.bonecp.BoneCPDataSource;
@@ -45,7 +47,8 @@ public class TestKillbillJdbcRealm extends ServerTestSuiteWithEmbeddedDB {
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
         // Create the tenant
-        final DefaultTenantDao tenantDao = new DefaultTenantDao(getDBI());
+        final CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
+        final DefaultTenantDao tenantDao = new DefaultTenantDao(getDBI(), clock, controllerDispatcher, new DefaultNonEntityDao(getDBI()));
         tenant = new DefaultTenant(UUID.randomUUID(), null, null, UUID.randomUUID().toString(),
                                    UUID.randomUUID().toString(), UUID.randomUUID().toString());
         tenantDao.create(new TenantModelDao(tenant), internalCallContext);
diff --git a/server/src/test/resources/shiro.ini b/server/src/test/resources/shiro.ini
index 21defe1..664ee13 100644
--- a/server/src/test/resources/shiro.ini
+++ b/server/src/test/resources/shiro.ini
@@ -33,4 +33,5 @@ jdbcRealm=com.ning.billing.server.security.KillbillJdbcRealm
 /1.0/kb/tenants/** = anon
 # For all other resources, require basic auth
 # TODO: ssl, authcBasic
-/1.0/kb/** = authcBasic
+# Commented out because that seems to break the server tests that don't require authentification
+#/1.0/kb/** = authcBasic
diff --git a/tenant/src/main/java/com/ning/billing/tenant/dao/DefaultTenantDao.java b/tenant/src/main/java/com/ning/billing/tenant/dao/DefaultTenantDao.java
index 959d8bd..7e8d901 100644
--- a/tenant/src/main/java/com/ning/billing/tenant/dao/DefaultTenantDao.java
+++ b/tenant/src/main/java/com/ning/billing/tenant/dao/DefaultTenantDao.java
@@ -32,8 +32,11 @@ import com.ning.billing.ErrorCode;
 import com.ning.billing.tenant.api.Tenant;
 import com.ning.billing.tenant.api.TenantApiException;
 import com.ning.billing.tenant.security.KillbillCredentialsMatcher;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntityDaoBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -51,8 +54,8 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
     private final RandomNumberGenerator rng = new SecureRandomNumberGenerator();
 
     @Inject
-    public DefaultTenantDao(final IDBI dbi) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi), TenantSqlDao.class);
+    public DefaultTenantDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), TenantSqlDao.class);
     }
 
     @Override
diff --git a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantKVModelDao.java b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantKVModelDao.java
index 362bbbe..cae8cac 100644
--- a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantKVModelDao.java
+++ b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantKVModelDao.java
@@ -104,4 +104,9 @@ public class TenantKVModelDao extends EntityBase implements EntityModelDao<Tenan
     public TableName getTableName() {
         return TableName.TENANT_KVS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
 }
diff --git a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantModelDao.java b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantModelDao.java
index 6422373..6163351 100644
--- a/tenant/src/main/java/com/ning/billing/tenant/dao/TenantModelDao.java
+++ b/tenant/src/main/java/com/ning/billing/tenant/dao/TenantModelDao.java
@@ -120,4 +120,9 @@ public class TenantModelDao extends EntityBase implements EntityModelDao<Tenant>
     public TableName getTableName() {
         return TableName.TENANT;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
 }
diff --git a/tenant/src/test/java/com/ning/billing/tenant/dao/TestDefaultTenantDao.java b/tenant/src/test/java/com/ning/billing/tenant/dao/TestDefaultTenantDao.java
index b8594bf..e3569e9 100644
--- a/tenant/src/test/java/com/ning/billing/tenant/dao/TestDefaultTenantDao.java
+++ b/tenant/src/test/java/com/ning/billing/tenant/dao/TestDefaultTenantDao.java
@@ -28,12 +28,16 @@ import org.testng.annotations.Test;
 import com.ning.billing.tenant.TenantTestSuiteWithEmbeddedDb;
 import com.ning.billing.tenant.api.DefaultTenant;
 import com.ning.billing.tenant.security.KillbillCredentialsMatcher;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
 
 public class TestDefaultTenantDao extends TenantTestSuiteWithEmbeddedDb {
 
+    private CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
+
     @Test(groups = "slow")
     public void testWeCanStoreAndMatchCredentials() throws Exception {
-        final DefaultTenantDao tenantDao = new DefaultTenantDao(getDBI());
+        final DefaultTenantDao tenantDao = new DefaultTenantDao(getDBI(), clock, controllerDispatcher, new DefaultNonEntityDao(getDBI()));
 
         final DefaultTenant tenant = new DefaultTenant(UUID.randomUUID(), null, null, UUID.randomUUID().toString(),
                                                        UUID.randomUUID().toString(), UUID.randomUUID().toString());
@@ -56,7 +60,7 @@ public class TestDefaultTenantDao extends TenantTestSuiteWithEmbeddedDb {
 
     @Test(groups = "slow")
     public void testTenantKeyValue() throws Exception {
-        final DefaultTenantDao tenantDao = new DefaultTenantDao(getDBI());
+        final DefaultTenantDao tenantDao = new DefaultTenantDao(getDBI(), clock, controllerDispatcher, new DefaultNonEntityDao(getDBI()));
         final DefaultTenant tenant = new DefaultTenant(UUID.randomUUID(), null, null, UUID.randomUUID().toString(),
                                                        UUID.randomUUID().toString(), UUID.randomUUID().toString());
         tenantDao.create(new TenantModelDao(tenant), internalCallContext);

util/pom.xml 5(+5 -0)

diff --git a/util/pom.xml b/util/pom.xml
index 2a1a92a..cf9e5bb 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -25,6 +25,11 @@
             <artifactId>killbill-api</artifactId>
         </dependency>
         <dependency>
+            <groupId>net.sf.ehcache</groupId>
+            <artifactId>ehcache-core</artifactId>
+            <type>jar</type>
+        </dependency>
+        <dependency>
             <groupId>com.jolbox</groupId>
             <artifactId>bonecp</artifactId>
         </dependency>
diff --git a/util/src/main/java/com/ning/billing/util/cache/AccountRecordIdCacheLoader.java b/util/src/main/java/com/ning/billing/util/cache/AccountRecordIdCacheLoader.java
new file mode 100644
index 0000000..9bc5a75
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/AccountRecordIdCacheLoader.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.tweak.HandleCallback;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.dao.TableName;
+
+import net.sf.ehcache.loader.CacheLoader;
+
+public class AccountRecordIdCacheLoader extends BaseCacheLoader implements CacheLoader {
+
+    @Inject
+    public AccountRecordIdCacheLoader(final IDBI dbi, final NonEntityDao nonEntityDao) {
+        super(dbi, nonEntityDao);
+    }
+
+    @Override
+    public Object load(final Object key, final Object argument) {
+
+        checkCacheLoaderStatus();
+
+        if (!(argument instanceof ObjectType)) {
+            throw new IllegalArgumentException("Unexpected argument type of " +
+                                               argument != null ? argument.getClass().getName() : "null");
+        }
+        if (!(key instanceof String)) {
+            throw new IllegalArgumentException("Unexpected key type of " +
+                                               key != null ? key.getClass().getName() : "null");
+
+        }
+        final String objectId = (String) key;
+        final ObjectType objectType = (ObjectType) argument;
+        Long value = nonEntityDao.retrieveAccountRecordIdFromObject(UUID.fromString(objectId), objectType, null);
+        return value;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/BaseCacheLoader.java b/util/src/main/java/com/ning/billing/util/cache/BaseCacheLoader.java
new file mode 100644
index 0000000..855fdef
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/BaseCacheLoader.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.util.Collection;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.util.dao.NonEntityDao;
+
+import net.sf.ehcache.CacheException;
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Status;
+import net.sf.ehcache.loader.CacheLoader;
+
+public abstract class BaseCacheLoader implements CacheLoader {
+
+    protected final IDBI dbi;
+    protected final NonEntityDao nonEntityDao;
+
+    private Status cacheLoaderStatus;
+
+    @Inject
+    public BaseCacheLoader(final IDBI dbi, final NonEntityDao nonEntityDao) {
+        this.dbi = dbi;
+        this.nonEntityDao = nonEntityDao;
+        this.cacheLoaderStatus = Status.STATUS_UNINITIALISED;
+    }
+
+    @Override
+    public abstract Object load(final Object key, final Object argument);
+
+
+    @Override
+    public Object load(final Object key) throws CacheException {
+        throw new IllegalStateException("Method load is not implemented ");
+    }
+
+    @Override
+    public Map loadAll(final Collection keys) {
+        throw new IllegalStateException("Method loadAll is not implemented ");
+    }
+
+    @Override
+    public Map loadAll(final Collection keys, final Object argument) {
+        throw new IllegalStateException("Method loadAll is not implemented ");
+    }
+
+    @Override
+    public String getName() {
+        return this.getClass().getName();
+    }
+
+    @Override
+    public CacheLoader clone(final Ehcache cache) throws CloneNotSupportedException {
+        throw new IllegalStateException("Method clone is not implemented ");
+    }
+
+    @Override
+    public void init() {
+        this.cacheLoaderStatus = Status.STATUS_ALIVE;
+    }
+
+    @Override
+    public void dispose() throws CacheException {
+        cacheLoaderStatus = Status.STATUS_SHUTDOWN;
+    }
+
+    @Override
+    public Status getStatus() {
+        return cacheLoaderStatus;
+    }
+
+    protected void checkCacheLoaderStatus() {
+        if (getStatus() != Status.STATUS_ALIVE) {
+            throw new CacheException("CacheLoader is not available!");
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/Cachable.java b/util/src/main/java/com/ning/billing/util/cache/Cachable.java
new file mode 100644
index 0000000..ac9e0ee
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/Cachable.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.UUID;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Cachable {
+
+    public final String RECORD_ID_CACHE_NAME = "record-id";
+    public final String ACCOUNT_RECORD_ID_CACHE_NAME = "account-record-id";
+    public final String TENANT_RECORD_ID_CACHE_NAME = "tenant-record-id";
+
+    public CacheType value();
+
+    public enum CacheType {
+        /* Mapping from object 'id (UUID)' -> object 'recordId (Long' */
+        RECORD_ID(RECORD_ID_CACHE_NAME, UUID.class, Long.class),
+
+        /* Mapping from object 'id (UUID)' -> matching account object 'accountRecordId (Long)' */
+        ACCOUNT_RECORD_ID(ACCOUNT_RECORD_ID_CACHE_NAME, UUID.class, Long.class),
+
+
+        /* Mapping from object 'id (UUID)' -> matching object 'tenantRecordId (Long)' */
+        TENANT_RECORD_ID(TENANT_RECORD_ID_CACHE_NAME, UUID.class, Long.class);
+
+        private final String cacheName;
+        private final Class key;
+        private final Class value;
+
+        CacheType(final String cacheName, final Class key, final Class value) {
+            this.cacheName = cacheName;
+            this.key = key;
+            this.value = value;
+        }
+
+        public Class getKey() {
+            return key;
+        }
+
+        public Class getValue() {
+            return value;
+        }
+
+        public static CacheType findByName(final String input) {
+            for (CacheType cur : CacheType.values()) {
+                if (cur.cacheName.equals(input)) {
+                    return cur;
+                }
+            }
+            return null;
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/CacheControllerDispatcher.java b/util/src/main/java/com/ning/billing/util/cache/CacheControllerDispatcher.java
new file mode 100644
index 0000000..ee9b3d0
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/CacheControllerDispatcher.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import com.ning.billing.util.cache.Cachable.CacheType;
+
+import com.google.inject.name.Named;
+
+public class CacheControllerDispatcher {
+
+    private final Map<CacheType, CacheController<?,?>> caches;
+
+    @Inject
+    public CacheControllerDispatcher(@Named(Cachable.RECORD_ID_CACHE_NAME) final CacheController<UUID, Long> recordIdCacheController,
+                                     @Named(Cachable.ACCOUNT_RECORD_ID_CACHE_NAME) final CacheController<UUID, Long> accountRecordIdCacheController,
+                                     @Named(Cachable.TENANT_RECORD_ID_CACHE_NAME) final CacheController<UUID, Long> tenantRecordIdCacheController) {
+        caches = new HashMap<CacheType, CacheController<?, ?>>();
+        caches.put(recordIdCacheController.getType(), recordIdCacheController);
+        caches.put(accountRecordIdCacheController.getType(), accountRecordIdCacheController);
+        caches.put(tenantRecordIdCacheController.getType(), tenantRecordIdCacheController);
+    }
+
+    // Test only
+    public CacheControllerDispatcher() {
+        caches = new HashMap<CacheType, CacheController<?, ?>>();
+    }
+
+    public <K,V> CacheController<K, V> getCacheController(CacheType cacheType) {
+        // STEPH Not the prettiest thing..
+        return  CacheController.class.cast(caches.get(cacheType));
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/CacheControllerProvider.java b/util/src/main/java/com/ning/billing/util/cache/CacheControllerProvider.java
new file mode 100644
index 0000000..cc715e5
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/CacheControllerProvider.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+
+import javax.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.util.cache.Cachable.CacheType;
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import com.google.inject.name.Names;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.loader.CacheLoader;
+
+public class CacheControllerProvider<K,V> implements Provider<CacheController<K, V>> {
+
+    private final static Logger logger = LoggerFactory.getLogger(CacheControllerProvider.class);
+
+    private CacheManager cacheManager;
+    private final String name;
+
+    private Injector injector;
+
+    public CacheControllerProvider(final String name) {
+        this.name = name;
+    }
+
+    @Inject
+    public void configure(final Injector injector, final CacheManager cacheManager) {
+        this.injector = injector;
+        this.cacheManager = cacheManager;
+    }
+
+    @Override
+    public CacheController<K, V> get() {
+
+        final Cache cache = cacheManager.getCache(name);
+        final Key<CacheLoader> cacheLoaderKey = Key.get(CacheLoader.class, Names.named(name));
+        final CacheLoader cacheLoader = injector.getInstance(cacheLoaderKey);
+
+        cacheLoader.init();
+
+        cache.registerCacheLoader(cacheLoader);
+
+        return new EhCacheBasedCacheController<K, V>(cache, CacheType.findByName(name));
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/CacheManagerProvider.java b/util/src/main/java/com/ning/billing/util/cache/CacheManagerProvider.java
new file mode 100644
index 0000000..83a68a8
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/CacheManagerProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.io.IOException;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.util.config.CacheConfig;
+
+import net.sf.ehcache.CacheManager;
+
+public class CacheManagerProvider implements Provider<CacheManager> {
+
+    private static final Logger log = LoggerFactory.getLogger(CacheManagerProvider.class);
+
+    private final CacheConfig cacheConfig;
+
+    private CacheManager cacheManager = null;
+
+    @Inject
+    public CacheManagerProvider(final CacheConfig cacheConfig) {
+        this.cacheConfig = cacheConfig;
+    }
+
+    @Override
+    public CacheManager get() {
+        synchronized (this) {
+            if (this.cacheManager == null) {
+                log.debug("Loading EHCache config from '%s'", cacheConfig.getCacheConfigLocation());
+
+                try {
+                    // Creates a singleton instance of the CacheManager
+                    this.cacheManager = CacheManager.create(CacheManagerProvider.class.getResource(cacheConfig.getCacheConfigLocation()).openStream());
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            return this.cacheManager;
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/EhCacheBasedCacheController.java b/util/src/main/java/com/ning/billing/util/cache/EhCacheBasedCacheController.java
new file mode 100644
index 0000000..623f1f7
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/EhCacheBasedCacheController.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.cache.Cachable.CacheType;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+public class EhCacheBasedCacheController<K, V> implements CacheController<K, V> {
+
+    private final Cache cache;
+    private final CacheType cacheType;
+
+    public EhCacheBasedCacheController(final Cache cache, final CacheType cacheType) {
+        this.cache = cache;
+        this.cacheType = cacheType;
+    }
+
+    @Override
+    public CacheType getType() {
+        return cacheType;
+    }
+
+    @Override
+    public V get(final K key, final ObjectType objectType) {
+        final Element element = cache.getWithLoader(key, null, objectType);
+        if (element == null) {
+            return null;
+        }
+        return (V) element.getObjectValue();
+    }
+
+    @Override
+    public boolean remove(final K key) {
+        return cache.remove(key);
+    }
+
+    @Override
+    public int size() {
+        return cache.getSize();
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/ExpirationListenerFactory.java b/util/src/main/java/com/ning/billing/util/cache/ExpirationListenerFactory.java
new file mode 100644
index 0000000..f592aac
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/ExpirationListenerFactory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.sf.ehcache.CacheException;
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.event.CacheEventListener;
+import net.sf.ehcache.event.CacheEventListenerFactory;
+
+public class ExpirationListenerFactory extends CacheEventListenerFactory {
+
+    private static final Logger log = LoggerFactory.getLogger(ExpirationListenerFactory.class);
+
+    @Override
+    public CacheEventListener createCacheEventListener(final Properties properties)
+    {
+        return new ExpirationListener();
+    }
+
+    private static class ExpirationListener implements CacheEventListener
+    {
+        @Override
+        public Object clone() throws CloneNotSupportedException
+        {
+            throw new CloneNotSupportedException("No cloning!");
+        }
+
+        @Override
+        public void dispose()
+        {
+        }
+
+        @Override
+        public void notifyElementEvicted(final Ehcache cache, final Element element)
+        {
+            if (log.isDebugEnabled()) {
+                log.debug("Cache Element " + element + " evicted!");
+            }
+        }
+
+        @Override
+        public void notifyElementExpired(final Ehcache cache, final Element element)
+        {
+            if (log.isDebugEnabled()) {
+                log.debug("Cache Element " + element + " expired!");
+            }
+        }
+
+        @Override
+        public void notifyElementPut(final Ehcache cache, final Element element) throws CacheException
+        {
+        }
+
+        @Override
+        public void notifyElementRemoved(final Ehcache cache, final Element element) throws CacheException
+        {
+        }
+
+        @Override
+        public void notifyElementUpdated(final Ehcache cache, final Element element) throws CacheException
+        {
+        }
+
+        @Override
+        public void notifyRemoveAll(final Ehcache cache)
+        {
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/RecordIdCacheLoader.java b/util/src/main/java/com/ning/billing/util/cache/RecordIdCacheLoader.java
new file mode 100644
index 0000000..3489753
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/RecordIdCacheLoader.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.dao.NonEntityDao;
+
+import net.sf.ehcache.CacheException;
+import net.sf.ehcache.loader.CacheLoader;
+
+public class RecordIdCacheLoader extends BaseCacheLoader implements CacheLoader {
+
+    @Inject
+    public RecordIdCacheLoader(final IDBI dbi, final NonEntityDao nonEntityDao) {
+        super(dbi, nonEntityDao);
+    }
+
+    @Override
+    public Object load(final Object key, final Object argument) throws CacheException {
+
+        checkCacheLoaderStatus();
+
+        if (!(argument instanceof ObjectType)) {
+            throw new IllegalArgumentException("Unexpected argument type of " +
+                                               argument != null ? argument.getClass().getName() : "null");
+        }
+        if (!(key instanceof String)) {
+            throw new IllegalArgumentException("Unexpected key type of " +
+                                               key != null ? key.getClass().getName() : "null");
+
+        }
+        final String objectId = (String) key;
+        final ObjectType objectType = (ObjectType) argument;
+        Long value = nonEntityDao.retrieveRecordIdFromObject(UUID.fromString(objectId), objectType, null);
+        return value;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/TenantRecordIdCacheLoader.java b/util/src/main/java/com/ning/billing/util/cache/TenantRecordIdCacheLoader.java
new file mode 100644
index 0000000..d8c2eb4
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/TenantRecordIdCacheLoader.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.dao.NonEntityDao;
+
+import net.sf.ehcache.loader.CacheLoader;
+
+public class TenantRecordIdCacheLoader  extends BaseCacheLoader implements CacheLoader {
+
+    @Inject
+    public TenantRecordIdCacheLoader(final IDBI dbi, final NonEntityDao nonEntityDao) {
+        super(dbi, nonEntityDao);
+    }
+
+    @Override
+    public Object load(final Object key, final Object argument) {
+
+        checkCacheLoaderStatus();
+
+        if (!(argument instanceof ObjectType)) {
+            throw new IllegalArgumentException("Unexpected argument type of " +
+                                               argument != null ? argument.getClass().getName() : "null");
+        }
+        if (!(key instanceof String)) {
+            throw new IllegalArgumentException("Unexpected key type of " +
+                                               key != null ? key.getClass().getName() : "null");
+
+        }
+        final String objectId = (String) key;
+        final ObjectType objectType = (ObjectType) argument;
+        Long value = nonEntityDao.retrieveTenantRecordIdFromObject(UUID.fromString(objectId), objectType, null);
+        return value;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
index 500313b..5a61f63 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
@@ -16,21 +16,18 @@
 
 package com.ning.billing.util.callcontext;
 
-import java.util.List;
-import java.util.Map;
 import java.util.UUID;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import org.joda.time.DateTime;
-import org.skife.jdbi.v2.Handle;
-import org.skife.jdbi.v2.IDBI;
-import org.skife.jdbi.v2.tweak.HandleCallback;
 
 import com.ning.billing.ObjectType;
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.dao.TableName;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.base.Objects;
 
@@ -38,15 +35,18 @@ public class InternalCallContextFactory {
 
     public static final long INTERNAL_TENANT_RECORD_ID = 0L;
 
-    private final IDBI dbi;
     private final Clock clock;
+    private final NonEntityDao nonEntityDao;
+    private final CacheControllerDispatcher cacheControllerDispatcher;
 
     @Inject
-    public InternalCallContextFactory(final IDBI dbi, final Clock clock) {
-        this.dbi = dbi;
+    public InternalCallContextFactory(final Clock clock, final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
         this.clock = clock;
+        this.nonEntityDao = nonEntityDao;
+        this.cacheControllerDispatcher = cacheControllerDispatcher;
     }
 
+
     /**
      * Create an internal tenant context from a tenant context
      * <p/>
@@ -143,8 +143,8 @@ public class InternalCallContextFactory {
                                                          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 = retrieveTenantRecordIdFromObject(objectId, objectType);
-        final Long accountRecordId = retrieveAccountRecordIdFromObject(objectId, objectType);
+        final Long tenantRecordId = nonEntityDao.retrieveTenantRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.TENANT_RECORD_ID));
+        final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
         return createInternalCallContext(tenantRecordId, accountRecordId, userName, callOrigin, userType, userToken,
                                          reasonCode, comment, createdDate, updatedDate);
     }
@@ -213,76 +213,7 @@ public class InternalCallContextFactory {
         if (context.getTenantId() == null) {
             return INTERNAL_TENANT_RECORD_ID;
         } else {
-            // We call onDemand here to avoid JDBI opening connections in the constructor.
-            // TODO should we cache it?
-            return dbi.onDemand(CallContextSqlDao.class).getTenantRecordId(context.getTenantId().toString());
-        }
-    }
-
-    private Long retrieveAccountRecordIdFromObject(final UUID objectId, final ObjectType objectType) {
-        final Long accountRecordId;
-
-        final TableName tableName = TableName.fromObjectType(objectType);
-        if (tableName != null) {
-            accountRecordId = dbi.withHandle(new HandleCallback<Long>() {
-                @Override
-                public Long withHandle(final Handle handle) throws Exception {
-                    final String columnName;
-                    if (TableName.TAG_DEFINITIONS.equals(tableName) || TableName.TAG_DEFINITION_HISTORY.equals(tableName)) {
-                        // Not tied to an account
-                        return null;
-                    } else if (TableName.ACCOUNT.equals(tableName) || TableName.ACCOUNT_HISTORY.equals(tableName)) {
-                        // Lookup the record_id directly
-                        columnName = "record_id";
-                    } else {
-                        // The table should have an account_record_id column
-                        columnName = "account_record_id";
-                    }
-
-                    final List<Map<String, Object>> values = handle.select(String.format("select %s from %s where id = ?;", columnName, tableName.getTableName()), objectId.toString());
-                    if (values.size() == 0) {
-                        return null;
-                    } else {
-                        final Object accountRecordId = values.get(0).get(columnName);
-                        return accountRecordId == null ? null : Long.valueOf(accountRecordId.toString());
-                    }
-                }
-            });
-        } else {
-            accountRecordId = null;
-        }
-        return accountRecordId;
-    }
-
-    private Long retrieveTenantRecordIdFromObject(final UUID objectId, final ObjectType objectType) {
-        final Long tenantRecordId;
-
-        final TableName tableName = TableName.fromObjectType(objectType);
-        if (tableName != null) {
-            tenantRecordId = dbi.withHandle(new HandleCallback<Long>() {
-                @Override
-                public Long withHandle(final Handle handle) throws Exception {
-                    final String columnName;
-                    if (TableName.TENANT.equals(tableName)) {
-                        // Lookup the record_id directly
-                        columnName = "record_id";
-                    } else {
-                        // The table should have an tenant_record_id column
-                        columnName = "tenant_record_id";
-                    }
-
-                    final List<Map<String, Object>> values = handle.select(String.format("select %s from %s where id = ?;", columnName, tableName.getTableName()), objectId.toString());
-                    if (values.size() == 0) {
-                        return null;
-                    } else {
-                        final Object tenantRecordId = values.get(0).get(columnName);
-                        return tenantRecordId == null ? null : Long.valueOf(tenantRecordId.toString());
-                    }
-                }
-            });
-        } else {
-            tenantRecordId = null;
+            return nonEntityDao.retrieveTenantRecordIdFromObject(context.getTenantId(), ObjectType.TENANT, cacheControllerDispatcher.getCacheController(CacheType.TENANT_RECORD_ID));
         }
-        return tenantRecordId;
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldModelDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldModelDao.java
index 1f166d5..04b08f3 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldModelDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldModelDao.java
@@ -121,4 +121,10 @@ public class CustomFieldModelDao extends EntityBase implements EntityModelDao<Cu
     public TableName getTableName() {
         return TableName.CUSTOM_FIELD;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.CUSTOM_FIELD_HISTORY;
+    }
+
 }
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/DefaultCustomFieldDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/DefaultCustomFieldDao.java
index 172229b..7f19fb0 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/DefaultCustomFieldDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/DefaultCustomFieldDao.java
@@ -24,9 +24,12 @@ import org.skife.jdbi.v2.IDBI;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.api.CustomFieldApiException;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntityDaoBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -38,8 +41,8 @@ import com.google.inject.Inject;
 public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, CustomField, CustomFieldApiException> implements CustomFieldDao {
 
     @Inject
-    public DefaultCustomFieldDao(final IDBI dbi) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi), CustomFieldSqlDao.class);
+    public DefaultCustomFieldDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao), CustomFieldSqlDao.class);
     }
 
     @Override
diff --git a/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java b/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java
new file mode 100644
index 0000000..793ceef
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.cache.CacheController;
+
+public class DefaultNonEntityDao implements NonEntityDao {
+
+    private final NonEntitySqlDao nonEntitySqlDao;
+    private final WithCaching containedCall;
+
+
+    @Inject
+    public DefaultNonEntityDao(final IDBI dbi) {
+        this.nonEntitySqlDao = dbi.onDemand(NonEntitySqlDao.class);
+        this.containedCall = new WithCaching();
+    }
+
+
+    public Long retrieveRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
+
+        return containedCall.withCaching(new OperationRetrieval<Long>() {
+            @Override
+            public Long doRetrieve(final UUID objectId, final ObjectType objectType) {
+                final TableName tableName = TableName.fromObjectType(objectType);
+                return nonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName());
+            }
+        }, objectId, objectType, cache);
+
+    }
+
+    public Long retrieveAccountRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
+
+
+        return containedCall.withCaching(new OperationRetrieval<Long>() {
+            @Override
+            public Long doRetrieve(final UUID objectId, final ObjectType objectType) {
+                final TableName tableName = TableName.fromObjectType(objectType);
+                switch (tableName) {
+                    case TENANT:
+                    case TAG_DEFINITIONS:
+                    case TAG_DEFINITION_HISTORY:
+                        return null;
+
+                    case ACCOUNT:
+                        return nonEntitySqlDao.getAccountRecordIdFromAccount(objectId.toString());
+
+                    default:
+                        return nonEntitySqlDao.getAccountRecordIdFromObjectOtherThanAccount(objectId.toString(), tableName.getTableName());
+                }
+            }
+        }, objectId, objectType, cache);
+    }
+
+
+    public Long retrieveTenantRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
+
+
+        return containedCall.withCaching(new OperationRetrieval<Long>() {
+            @Override
+            public Long doRetrieve(final UUID objectId, final ObjectType objectType) {
+                final TableName tableName = TableName.fromObjectType(objectType);
+                switch (tableName) {
+                    case TENANT:
+                        return nonEntitySqlDao.getTenantRecordIdFromTenant(objectId.toString());
+
+                    default:
+                        return nonEntitySqlDao.getTenantRecordIdFromObjectOtherThanTenant(objectId.toString(), tableName.getTableName());
+                }
+
+            }
+        }, objectId, objectType, cache);
+    }
+
+    @Override
+    public Long retrieveLastHistoryRecordIdFromTransaction(final Long targetRecordId, final TableName tableName, final NonEntitySqlDao transactional) {
+        // There is no caching here because the value returned changes as we add more history records, and so we would need some cache invalidation
+        return transactional.getLastHistoryRecordId(targetRecordId, tableName.getTableName());
+    }
+
+    @Override
+    public Long retrieveHistoryTargetRecordId(final Long recordId, final TableName tableName) {
+        return nonEntitySqlDao.getHistoryTargetRecordId(recordId, tableName.getTableName());
+    }
+
+
+    private interface OperationRetrieval<T> {
+        public T doRetrieve(final UUID objectId, final ObjectType objectType);
+    }
+
+
+    // 'cache' will be null for the CacheLoader classes -- or if cache is not configured.
+    private class WithCaching {
+        private Long withCaching(final OperationRetrieval<Long> op, final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
+            if (cache != null) {
+                final Long cachedResult = (Long) cache.get(objectId.toString(), objectType);
+                return cachedResult;
+            }
+            return op.doRetrieve(objectId, objectType);
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/NonEntityDao.java b/util/src/main/java/com/ning/billing/util/dao/NonEntityDao.java
new file mode 100644
index 0000000..26be4a4
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/NonEntityDao.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.cache.CacheController;
+import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
+
+public interface NonEntityDao {
+
+    //
+    // TODO should we check for InternalCallContext?
+    // That seems difficult because those APIs are called when creating a context or from the cache loaders which also dpn't know anything about context
+    //
+    public Long retrieveRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache);
+
+    public Long retrieveAccountRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache);
+
+    public Long retrieveTenantRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache);
+
+    // This retrieves from the history table the latest record for which targetId matches the one we are passing
+    public Long retrieveLastHistoryRecordIdFromTransaction(final Long targetRecordId, final TableName tableName, final NonEntitySqlDao transactional);
+
+    //This is the reverse from retrieveLastHistoryRecordIdFromTransaction; this retrieves the record_id of the object matching a given history row
+    public Long retrieveHistoryTargetRecordId(final Long recordId, final TableName tableName);
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/NonEntitySqlDao.java b/util/src/main/java/com/ning/billing/util/dao/NonEntitySqlDao.java
new file mode 100644
index 0000000..f0a119d
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/NonEntitySqlDao.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.customizers.Define;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator;
+
+@UseStringTemplate3StatementLocator
+public interface NonEntitySqlDao extends Transactional<NonEntitySqlDao>, CloseMe {
+
+    @SqlQuery
+    public Long getRecordIdFromObject(@Bind("id") String id, @Define("tableName") final String tableName);
+
+    @SqlQuery
+    public Long getAccountRecordIdFromAccount(@Bind("id") String id);
+
+    @SqlQuery
+    public Long getAccountRecordIdFromAccountHistory(@Bind("id") String id);
+
+    @SqlQuery
+    public Long getAccountRecordIdFromObjectOtherThanAccount(@Bind("id") String id, @Define("tableName") final String tableName);
+
+    @SqlQuery
+    public Long getTenantRecordIdFromTenant(@Bind("id") String id);
+
+    @SqlQuery
+    public Long getTenantRecordIdFromObjectOtherThanTenant(@Bind("id") String id, @Define("tableName") final String tableName);
+
+    @SqlQuery
+    public Long getLastHistoryRecordId(@Bind("targetRecordId") Long targetRecordId, @Define("tableName") final String tableName);
+
+    @SqlQuery
+    public Long getHistoryTargetRecordId(@Bind("recordId") Long recordId, @Define("tableName") final String tableName);
+}
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntityModelDao.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntityModelDao.java
index 5e0e02f..d822a32 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntityModelDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntityModelDao.java
@@ -35,4 +35,7 @@ public interface EntityModelDao<E extends Entity> extends Entity {
      * @return the TableName object associated with this ModelDao entity
      */
     public TableName getTableName();
+
+
+    public TableName getHistoryTableName();
 }
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
index 58243d3..418dbee 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
@@ -27,6 +27,8 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
 import com.ning.billing.util.audit.ChangeType;
+import com.ning.billing.util.cache.Cachable;
+import com.ning.billing.util.cache.Cachable.CacheType;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.dao.AuditSqlDao;
@@ -54,19 +56,10 @@ public interface EntitySqlDao<M extends EntityModelDao<E>, E extends Entity> ext
                            @BindBean final InternalTenantContext context);
 
     @SqlQuery
+    @Cachable(CacheType.RECORD_ID)
     public Long getRecordId(@Bind("id") final String id,
                             @BindBean final InternalTenantContext context);
 
-    // Given entity recordId find the history recordId (targetRecordId for history table = entity recordId)
-    @SqlQuery
-    public Long getHistoryRecordId(@Bind("targetRecordId") final Long targetRecordId,
-                                   @BindBean final InternalTenantContext context);
-
-    // Given history recordId find the entity recordId (targetRecordId for history table = entity recordId)
-    @SqlQuery
-    public Long getHistoryTargetRecordId(@Bind("recordId") final Long recordId,
-                                         @BindBean final InternalTenantContext context);
-
     @SqlQuery
     public List<M> get(@BindBean final InternalTenantContext context);
 
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
index 13ba96c..35098ca 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
@@ -20,6 +20,9 @@ import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.Transaction;
 import org.skife.jdbi.v2.TransactionStatus;
 
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.Entity;
 
 /**
@@ -28,9 +31,15 @@ import com.ning.billing.util.entity.Entity;
 public class EntitySqlDaoTransactionalJdbiWrapper {
 
     private final IDBI dbi;
+    private final Clock clock;
+    private final CacheControllerDispatcher cacheControllerDispatcher;
+    private final NonEntityDao nonEntityDao;
 
-    public EntitySqlDaoTransactionalJdbiWrapper(final IDBI dbi) {
+    public EntitySqlDaoTransactionalJdbiWrapper(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
         this.dbi = dbi;
+        this.clock = clock;
+        this.cacheControllerDispatcher = cacheControllerDispatcher;
+        this.nonEntityDao = nonEntityDao;
     }
 
     class JdbiTransaction<ReturnType, M extends EntityModelDao<E>, E extends Entity> implements Transaction<ReturnType, EntitySqlDao<M, E>> {
@@ -43,7 +52,7 @@ public class EntitySqlDaoTransactionalJdbiWrapper {
 
         @Override
         public ReturnType inTransaction(final EntitySqlDao<M, E> transactionalSqlDao, final TransactionStatus status) throws Exception {
-            final EntitySqlDaoWrapperFactory<EntitySqlDao> factoryEntitySqlDao = new EntitySqlDaoWrapperFactory<EntitySqlDao>(transactionalSqlDao);
+            final EntitySqlDaoWrapperFactory<EntitySqlDao> factoryEntitySqlDao = new EntitySqlDaoWrapperFactory<EntitySqlDao>(transactionalSqlDao, clock, cacheControllerDispatcher, nonEntityDao);
             return entitySqlDaoTransactionWrapper.inTransaction(factoryEntitySqlDao);
         }
     }
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
index b9dd2d4..08d5a35 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
@@ -18,6 +18,9 @@ package com.ning.billing.util.entity.dao;
 
 import java.lang.reflect.Proxy;
 
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.Entity;
 
 /**
@@ -30,9 +33,16 @@ import com.ning.billing.util.entity.Entity;
 public class EntitySqlDaoWrapperFactory<InitialSqlDao extends EntitySqlDao> {
 
     private final InitialSqlDao sqlDao;
+    private final Clock clock;
+    private final CacheControllerDispatcher cacheControllerDispatcher;
 
-    public EntitySqlDaoWrapperFactory(final InitialSqlDao sqlDao) {
+    private final NonEntityDao nonEntityDao;
+
+    public EntitySqlDaoWrapperFactory(final InitialSqlDao sqlDao, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
         this.sqlDao = sqlDao;
+        this.clock = clock;
+        this.cacheControllerDispatcher = cacheControllerDispatcher;
+        this.nonEntityDao = nonEntityDao;
     }
 
     /**
@@ -59,7 +69,7 @@ public class EntitySqlDaoWrapperFactory<InitialSqlDao extends EntitySqlDao> {
         final ClassLoader classLoader = newSqlDao.getClass().getClassLoader();
         final Class[] interfacesToImplement = {newSqlDaoClass};
         final EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntityModelDao, NewEntity> wrapperInvocationHandler =
-                new EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntityModelDao, NewEntity>(newSqlDaoClass, newSqlDao);
+                new EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntityModelDao, NewEntity>(newSqlDaoClass, newSqlDao, clock, cacheControllerDispatcher, nonEntityDao);
 
         final Object newSqlDaoObject = Proxy.newProxyInstance(classLoader, interfacesToImplement, wrapperInvocationHandler);
         return newSqlDaoClass.cast(newSqlDaoObject);
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index 1ded618..0cd07c6 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -18,13 +18,16 @@ package com.ning.billing.util.entity.dao;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import org.skife.jdbi.v2.Binding;
 import org.skife.jdbi.v2.StatementContext;
@@ -34,12 +37,21 @@ import org.skife.jdbi.v2.sqlobject.Bind;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.ObjectType;
 import com.ning.billing.util.audit.ChangeType;
+import com.ning.billing.util.cache.Cachable;
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.cache.CacheController;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.dao.EntityAudit;
 import com.ning.billing.util.dao.EntityHistoryModelDao;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.dao.NonEntitySqlDao;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.Entity;
+import com.ning.billing.util.tag.dao.TagSqlDao;
 
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
@@ -59,9 +71,16 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
     private final Class<S> sqlDaoClass;
     private final S sqlDao;
 
-    public EntitySqlDaoWrapperInvocationHandler(final Class<S> sqlDaoClass, final S sqlDao) {
+    private final CacheControllerDispatcher cacheControllerDispatcher;
+    private final Clock clock;
+    private final NonEntityDao nonEntityDao;
+
+    public EntitySqlDaoWrapperInvocationHandler(final Class<S> sqlDaoClass, final S sqlDao, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
         this.sqlDaoClass = sqlDaoClass;
         this.sqlDao = sqlDao;
+        this.clock = clock;
+        this.cacheControllerDispatcher = cacheControllerDispatcher;
+        this.nonEntityDao = nonEntityDao;
     }
 
     @Override
@@ -134,13 +153,87 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
     }
 
     private Object invokeSafely(final Object proxy, final Method method, final Object[] args) throws Throwable {
-        final Audited annotation = method.getAnnotation(Audited.class);
 
+        final Audited auditedAnnotation = method.getAnnotation(Audited.class);
+        final Cachable cachableAnnotation = method.getAnnotation(Cachable.class);
+
+        // This can't be AUDIT'ed and CACHABLE'd at the same time as we only cache 'get'
+        if (auditedAnnotation != null) {
+            return invokeWithAuditAndHistory(auditedAnnotation, method, args);
+        } else if (cachableAnnotation != null) {
+            return invokeWithCaching(cachableAnnotation, method, args);
+        } else {
+            return method.invoke(sqlDao, args);
+        }
+    }
+
+    private Object invokeWithCaching(final Cachable cachableAnnotation, final Method method, final Object[] args)
+            throws IllegalAccessException, InvocationTargetException, ClassNotFoundException, InstantiationException {
+
+        final ObjectType objectType = getObjectType();
+        final CacheType cacheType = cachableAnnotation.value();
+        final CacheController<Object, Object> cache = cacheControllerDispatcher.getCacheController(cacheType);
+        Object result = null;
+        if (cache != null) {
+            // STEPH : Assume first argument is the key for the cache, this is a bit fragile...
+            result = cache.get(args[0], objectType);
+        }
+        if (result == null) {
+            result = method.invoke(sqlDao, args);
+        }
+        return result;
+    }
+
+    /**
+     * Extract object from sqlDaoClass by looking at first parameter type (EntityModelDao) and
+     * constructing an empty object so we can call the getObjectType method on it.
+     *
+     * @return the objectType associated to that handler
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     * @throws ClassNotFoundException
+     */
+    private ObjectType getObjectType() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+
+        int foundIndexForEntitySqlDao = -1;
+        // If the sqlDaoClass implements multiple interfaces, first figure out which one is the EntitySqlDao
+        for (int i = 0; i < sqlDaoClass.getGenericInterfaces().length; i++) {
+            if (EntitySqlDao.class.getName().equals(((Class) ((java.lang.reflect.ParameterizedType) sqlDaoClass.getGenericInterfaces()[0]).getRawType()).getName())) {
+                foundIndexForEntitySqlDao = i;
+                break;
+            }
+        }
+        // Find out from the parameters of the EntitySqlDao which one is the EntityModelDao, and extract his (sub)type to finally return the ObjectType
+        if (foundIndexForEntitySqlDao >= 0) {
+            Type[] types = ((java.lang.reflect.ParameterizedType) sqlDaoClass.getGenericInterfaces()[foundIndexForEntitySqlDao]).getActualTypeArguments();
+            int foundIndexForEntityModelDao = -1;
+            for (int i = 0; i < types.length; i++) {
+                Class clz = ((Class) types[i]);
+                if (EntityModelDao.class.getName().equals(((Class) ((java.lang.reflect.ParameterizedType) clz.getGenericInterfaces()[0]).getRawType()).getName())) {
+                    foundIndexForEntityModelDao = i;
+                    break;
+                }
+            }
+
+            if (foundIndexForEntityModelDao >= 0) {
+                String modelClassName = ((Class) types[foundIndexForEntityModelDao]).getName();
+
+                Class<? extends EntityModelDao<?>> clz = (Class<? extends EntityModelDao<?>>) Class.forName(modelClassName);
+
+                EntityModelDao<?> modelDao = (EntityModelDao<?>) clz.newInstance();
+                return modelDao.getTableName().getObjectType();
+            }
+        }
+        return null;
+    }
+
+
+    private Object invokeWithAuditAndHistory(final Audited auditedAnnotation, final Method method, final Object[] args) throws IllegalAccessException, InvocationTargetException {
         InternalCallContext context = null;
         List<String> entityIds = null;
         final Map<String, M> entities = new HashMap<String, M>();
         final Map<String, Long> entityRecordIds = new HashMap<String, Long>();
-        if (annotation != null) {
+        if (auditedAnnotation != null) {
             // There will be some work required after the statement is executed,
             // get the id before in case the change is a delete
             context = retrieveContextFromArguments(args);
@@ -154,15 +247,11 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
         // Real jdbc call
         final Object obj = method.invoke(sqlDao, args);
 
-        // Update audit and history if needed
-        if (annotation != null) {
-            final ChangeType changeType = annotation.value();
+        final ChangeType changeType = auditedAnnotation.value();
 
-            for (final String entityId : entityIds) {
-                updateHistoryAndAudit(entityId, entities, entityRecordIds, changeType, context);
-            }
+        for (final String entityId : entityIds) {
+            updateHistoryAndAudit(entityId, entities, entityRecordIds, changeType, context);
         }
-
         return obj;
     }
 
@@ -250,16 +339,19 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
     }
 
     private Long insertHistory(final Long entityRecordId, final M entityModelDao, final ChangeType changeType, final InternalCallContext context) {
-        // TODO use clock
-        final EntityHistoryModelDao<M, E> history = new EntityHistoryModelDao<M, E>(entityModelDao, entityRecordId, changeType, context.getCreatedDate());
+        final EntityHistoryModelDao<M, E> history = new EntityHistoryModelDao<M, E>(entityModelDao, entityRecordId, changeType, clock.getUTCNow());
+
         sqlDao.addHistoryFromTransaction(history, context);
-        return sqlDao.getHistoryRecordId(entityRecordId, context);
+
+        final NonEntitySqlDao transactional = sqlDao.become(NonEntitySqlDao.class);
+
+        /* return transactional.getLastHistoryRecordId(entityRecordId, entityModelDao.getHistoryTableName().getTableName()); */
+        return nonEntityDao.retrieveLastHistoryRecordIdFromTransaction(entityRecordId, entityModelDao.getHistoryTableName(), transactional);
     }
 
     private void insertAudits(final TableName tableName, final Long historyRecordId, final ChangeType changeType, final InternalCallContext context) {
-        // TODO use clock
         final TableName destinationTableName = Objects.firstNonNull(tableName.getHistoryTableName(), tableName);
-        final EntityAudit audit = new EntityAudit(destinationTableName, historyRecordId, changeType, context.getCreatedDate());
+        final EntityAudit audit = new EntityAudit(destinationTableName, historyRecordId, changeType, clock.getUTCNow());
         sqlDao.insertAuditFromTransaction(audit, context);
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/glue/CacheModule.java b/util/src/main/java/com/ning/billing/util/glue/CacheModule.java
new file mode 100644
index 0000000..a304b3c
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/glue/CacheModule.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.glue;
+
+import java.util.UUID;
+
+import org.skife.config.ConfigSource;
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.config.SimplePropertyConfigSource;
+
+import com.ning.billing.util.cache.AccountRecordIdCacheLoader;
+import com.ning.billing.util.cache.Cachable;
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.cache.CacheController;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.cache.CacheControllerProvider;
+import com.ning.billing.util.cache.CacheManagerProvider;
+import com.ning.billing.util.cache.RecordIdCacheLoader;
+import com.ning.billing.util.cache.TenantRecordIdCacheLoader;
+import com.ning.billing.util.config.CacheConfig;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Singleton;
+import com.google.inject.TypeLiteral;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.loader.CacheLoader;
+
+public class CacheModule extends AbstractModule {
+
+
+    public static final Named RECORD_ID_CACHE_NAMED = Names.named(Cachable.RECORD_ID_CACHE_NAME);
+    public static final Named ACCOUNT_RECORD_ID_CACHE_NAMED = Names.named(Cachable.ACCOUNT_RECORD_ID_CACHE_NAME);
+    public static final Named TENANT_RECORD_ID_CACHE_NAMED = Names.named(Cachable.TENANT_RECORD_ID_CACHE_NAME);
+
+    protected void installConfig() {
+        final ConfigSource configSource = new SimplePropertyConfigSource(System.getProperties());
+        final CacheConfig config = new ConfigurationObjectFactory(configSource).build(CacheConfig.class);
+        bind(CacheConfig.class).toInstance(config);
+    }
+
+    @Override
+    protected void configure() {
+
+        installConfig();
+
+        bind(CacheManager.class).toProvider(CacheManagerProvider.class).asEagerSingleton();
+
+        bind(CacheLoader.class).annotatedWith(RECORD_ID_CACHE_NAMED).to(RecordIdCacheLoader.class).asEagerSingleton();
+        bind(new TypeLiteral<CacheController<UUID, Long>>() {}).annotatedWith(RECORD_ID_CACHE_NAMED).toProvider(new CacheControllerProvider<UUID, Long>(Cachable.RECORD_ID_CACHE_NAME)).asEagerSingleton();
+
+        bind(CacheLoader.class).annotatedWith(ACCOUNT_RECORD_ID_CACHE_NAMED).to(AccountRecordIdCacheLoader.class).asEagerSingleton();
+        bind(new TypeLiteral<CacheController<UUID, Long>>() {}).annotatedWith(ACCOUNT_RECORD_ID_CACHE_NAMED).toProvider(new CacheControllerProvider<UUID, Long>(Cachable.ACCOUNT_RECORD_ID_CACHE_NAME)).asEagerSingleton();
+
+        bind(CacheLoader.class).annotatedWith(TENANT_RECORD_ID_CACHE_NAMED).to(TenantRecordIdCacheLoader.class).asEagerSingleton();
+        bind(new TypeLiteral<CacheController<UUID, Long>>() {}).annotatedWith(TENANT_RECORD_ID_CACHE_NAMED).toProvider(new CacheControllerProvider<UUID, Long>(Cachable.TENANT_RECORD_ID_CACHE_NAME)).asEagerSingleton();
+
+        bind(CacheControllerDispatcher.class).asEagerSingleton();
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/glue/CallContextModule.java b/util/src/main/java/com/ning/billing/util/glue/CallContextModule.java
index a287c37..5a0b43e 100644
--- a/util/src/main/java/com/ning/billing/util/glue/CallContextModule.java
+++ b/util/src/main/java/com/ning/billing/util/glue/CallContextModule.java
@@ -18,6 +18,7 @@ package com.ning.billing.util.glue;
 
 import com.ning.billing.util.callcontext.CallContextFactory;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
 
 import com.google.inject.AbstractModule;
 
@@ -25,5 +26,6 @@ public class CallContextModule extends AbstractModule {
     @Override
     protected void configure() {
         bind(CallContextFactory.class).to(DefaultCallContextFactory.class).asEagerSingleton();
+        bind(InternalCallContextFactory.class).asEagerSingleton();
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
index 59379fc..208a211 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
@@ -28,9 +28,13 @@ import org.skife.jdbi.v2.tweak.HandleCallback;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.ObjectType;
 import com.ning.billing.util.Hostname;
 
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
@@ -55,15 +59,21 @@ public class DefaultNotificationQueue implements NotificationQueue {
     private final NotificationQueueHandler handler;
 
     private final NotificationQueueService notificationQueueService;
+    private final NonEntityDao nonEntityDao;
+    private final CacheControllerDispatcher cacheControllerDispatcher;
+
 
     private volatile boolean isStarted;
 
     public DefaultNotificationQueue(final String svcName, final String queueName, final NotificationQueueHandler handler,
-                                    final IDBI dbi, final NotificationQueueService notificationQueueService) {
+                                    final IDBI dbi, final NotificationQueueService notificationQueueService,
+                                    final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
         this.svcName = svcName;
         this.queueName = queueName;
         this.handler = handler;
         this.dbi = dbi;
+        this.nonEntityDao = nonEntityDao;
+        this.cacheControllerDispatcher = cacheControllerDispatcher;
         this.dao = dbi.onDemand(NotificationSqlDao.class);
         this.hostname = Hostname.get();
         this.notificationQueueService = notificationQueueService;
@@ -108,19 +118,7 @@ public class DefaultNotificationQueue implements NotificationQueue {
 
     @Override
     public List<Notification> getNotificationForAccountAndDate(final UUID accountId, final DateTime effectiveDate, final InternalCallContext context) {
-        // TODO we have the same use case in InternalCallContextFactory, do we need some sort of helper class?
-        final Long accountRecordId = dbi.withHandle(new HandleCallback<Long>() {
-            @Override
-            public Long withHandle(final Handle handle) throws Exception {
-                final List<Map<String, Object>> values = handle.select("select record_id from accounts where id = " + accountId.toString());
-                if (values.size() == 0) {
-                    return null;
-                } else {
-                    return (Long) values.get(0).get("record_id");
-                }
-            }
-        });
-
+        final Long accountRecordId = nonEntityDao.retrieveRecordIdFromObject(accountId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
         if (accountId == null) {
             return ImmutableList.<Notification>of();
         } else {
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueueService.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueueService.java
index dcb7e0b..d1a31db 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueueService.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueueService.java
@@ -18,20 +18,27 @@ package com.ning.billing.util.notificationq;
 
 import org.skife.jdbi.v2.IDBI;
 
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.inject.Inject;
 
 public class DefaultNotificationQueueService extends NotificationQueueServiceBase {
 
     private final IDBI dbi;
+    private final NonEntityDao nonEntityDao;
+    private final CacheControllerDispatcher cacheControllerDispatcher;
+
 
     @Inject
     public DefaultNotificationQueueService(final IDBI dbi, final Clock clock, final NotificationQueueConfig config,
-                                           final InternalCallContextFactory internalCallContextFactory) {
+                                           final InternalCallContextFactory internalCallContextFactory, final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
         super(clock, config, dbi, internalCallContextFactory);
         this.dbi = dbi;
+        this.nonEntityDao = nonEntityDao;
+        this.cacheControllerDispatcher = cacheControllerDispatcher;
     }
 
 
@@ -39,6 +46,6 @@ public class DefaultNotificationQueueService extends NotificationQueueServiceBas
     protected NotificationQueue createNotificationQueueInternal(final String svcName,
                                                                 final String queueName,
                                                                 final NotificationQueueHandler handler) {
-        return new DefaultNotificationQueue(svcName, queueName, handler, dbi, this);
+        return new DefaultNotificationQueue(svcName, queueName, handler, dbi, this, nonEntityDao, cacheControllerDispatcher);
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDao.java
index d40fbf4..cd5a164 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDao.java
@@ -28,8 +28,11 @@ import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.audit.ChangeType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntityDaoBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -51,8 +54,9 @@ public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiExcepti
     private final InternalBus bus;
 
     @Inject
-    public DefaultTagDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final InternalBus bus) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi), TagSqlDao.class);
+    public DefaultTagDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final InternalBus bus, final Clock clock,
+                         final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao), TagSqlDao.class);
         this.tagEventBuilder = tagEventBuilder;
         this.bus = bus;
     }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
index 968c957..8b8b2fd 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -30,8 +30,11 @@ import com.ning.billing.BillingExceptionBase;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.audit.ChangeType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntityDaoBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -55,8 +58,9 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
     private final InternalBus bus;
 
     @Inject
-    public DefaultTagDefinitionDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final InternalBus bus) {
-        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi), TagDefinitionSqlDao.class);
+    public DefaultTagDefinitionDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final InternalBus bus, final Clock clock,
+                                   final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao), TagDefinitionSqlDao.class);
         this.tagEventBuilder = tagEventBuilder;
         this.bus = bus;
     }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionModelDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionModelDao.java
index 5c0aaf9..10acfb9 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionModelDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionModelDao.java
@@ -117,4 +117,10 @@ public class TagDefinitionModelDao extends EntityBase implements EntityModelDao<
     public TableName getTableName() {
         return TableName.TAG_DEFINITIONS;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.TAG_DEFINITION_HISTORY;
+    }
+
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagModelDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagModelDao.java
index 8d381df..ea6ce3f 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagModelDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagModelDao.java
@@ -125,4 +125,10 @@ public class TagModelDao extends EntityBase implements EntityModelDao<Tag> {
     public TableName getTableName() {
         return TableName.TAG;
     }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return TableName.TAG_HISTORY;
+    }
+
 }
diff --git a/util/src/main/resources/com/ning/billing/util/dao/NonEntitySqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/dao/NonEntitySqlDao.sql.stg
new file mode 100644
index 0000000..3e11edb
--- /dev/null
+++ b/util/src/main/resources/com/ning/billing/util/dao/NonEntitySqlDao.sql.stg
@@ -0,0 +1,67 @@
+group NonEntitySqlDao;
+
+getRecordIdFromObject(tableName) ::= <<
+select
+  record_id
+from <tableName>
+where id = :id
+;
+>>
+
+getAccountRecordIdFromAccountHistory() ::= <<
+select
+  target_record_id
+from account_history
+where id = :id
+;
+>>
+
+getAccountRecordIdFromAccount() ::= <<
+select
+  record_id
+from accounts
+where id = :id
+;
+>>
+
+getAccountRecordIdFromObjectOtherThanAccount(tableName) ::= <<
+select
+  account_record_id
+from <tableName>
+where id = :id
+;
+>>
+
+getTenantRecordIdFromTenant() ::= <<
+select
+  record_id
+from tenants
+where id = :id
+;
+>>
+
+getTenantRecordIdFromObjectOtherThanTenant(tableName) ::= <<
+select
+  tenant_record_id
+from <tableName>
+where id = :id
+;
+>>
+
+
+getLastHistoryRecordId(tableName) ::= <<
+select
+  max(record_id)
+from <tableName>
+where target_record_id = :targetRecordId
+;
+>>
+
+getHistoryTargetRecordId(tableName) ::= <<
+select
+  target_record_id
+from <tableName>
+where record_id = :recordId
+;
+>>
+
diff --git a/util/src/main/resources/ehcache.xml b/util/src/main/resources/ehcache.xml
new file mode 100644
index 0000000..ac86fe3
--- /dev/null
+++ b/util/src/main/resources/ehcache.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Copyright 2010-2012 Ning, Inc.
+  ~
+  ~ Ning licenses this file to you under the Apache License, version 2.0
+  ~ (the "License"); you may not use this file except in compliance with the
+  ~ License.  You may obtain a copy of the License at:
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+  ~ License for the specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="ehcache.xsd" >
+
+  <defaultCache
+      maxElementsInMemory="0"
+      maxElementsOnDisk="0"
+      eternal="false"
+      timeToIdleSeconds="0"
+      timeToLiveSeconds="0"
+      overflowToDisk="false"
+      />
+
+    <cache name="record-id"
+           maxElementsInMemory="100000"
+           maxElementsOnDisk="0"
+           eternal="true"
+           overflowToDisk="false"
+           diskPersistent="false"
+           memoryStoreEvictionPolicy="LFU">
+        <cacheEventListenerFactory
+                class="com.ning.billing.util.cache.ExpirationListenerFactory"
+                properties="" />
+    </cache>
+
+    <cache name="tenant-record-id"
+           maxElementsInMemory="100000"
+           maxElementsOnDisk="0"
+           eternal="true"
+           overflowToDisk="false"
+           diskPersistent="false"
+           memoryStoreEvictionPolicy="LFU">
+        <cacheEventListenerFactory
+                class="com.ning.billing.util.cache.ExpirationListenerFactory"
+                properties="" />
+    </cache>
+
+    <cache name="account-record-id"
+           maxElementsInMemory="100000"
+           maxElementsOnDisk="0"
+           eternal="true"
+           overflowToDisk="false"
+           diskPersistent="false"
+           memoryStoreEvictionPolicy="LFU">
+        <cacheEventListenerFactory
+                class="com.ning.billing.util.cache.ExpirationListenerFactory"
+                properties="" />
+    </cache>
+</ehcache>
+
diff --git a/util/src/test/java/com/ning/billing/dao/MockNonEntityDao.java b/util/src/test/java/com/ning/billing/dao/MockNonEntityDao.java
new file mode 100644
index 0000000..4444bdf
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/dao/MockNonEntityDao.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.dao;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.cache.CacheController;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.dao.NonEntitySqlDao;
+import com.ning.billing.util.dao.TableName;
+
+public class MockNonEntityDao implements NonEntityDao {
+
+    @Override
+    public Long retrieveRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
+        return null;
+    }
+
+    @Override
+    public Long retrieveAccountRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
+        return null;
+    }
+
+    @Override
+    public Long retrieveTenantRecordIdFromObject(final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
+        return null;
+    }
+
+    @Override
+    public Long retrieveLastHistoryRecordIdFromTransaction(final Long targetRecordId, final TableName tableName, final NonEntitySqlDao transactional) {
+        return null;
+    }
+
+    @Override
+    public Long retrieveHistoryTargetRecordId(final Long recordId, final TableName tableName) {
+        return null;
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/dbi/DBTestingHelper.java b/util/src/test/java/com/ning/billing/dbi/DBTestingHelper.java
index 65a3e9a..a2241c5 100644
--- a/util/src/test/java/com/ning/billing/dbi/DBTestingHelper.java
+++ b/util/src/test/java/com/ning/billing/dbi/DBTestingHelper.java
@@ -47,14 +47,14 @@ public abstract class DBTestingHelper {
     protected IDBI dbiInstance = null;
 
     public synchronized IDBI getDBI() {
-        if (dbiInstance == null) {
-            final String dbiString = getJdbcConnectionString();
-            dbiInstance = new DBIProvider(dbiString, USERNAME, PASSWORD).get();
-        }
+        createInstanceIfNull();
         return dbiInstance;
     }
 
     public void initDb() throws IOException {
+
+        createInstanceIfNull();
+
         // We always want the accounts and tenants table
         initDb("drop table if exists accounts;" +
                "CREATE TABLE accounts (\n" +
@@ -87,7 +87,8 @@ public abstract class DBTestingHelper {
                "    tenant_record_id int(11) unsigned default null,\n" +
                "    PRIMARY KEY(record_id)\n" +
                ");");
-        initDb("drop table if exists tenants; create table tenants(record_id int(11) unsigned not null auto_increment, id char(36) not null, primary key(record_id));");
+        initDb("drop table if exists tenants; create table tenants(record_id int(11) unsigned not null auto_increment, id char(36) not null, external_key varchar(128) NULL, api_key varchar(128) NULL, " +
+               "api_secret varchar(128) NULL, api_salt varchar(128) NULL, created_date datetime NOT NULL, created_by varchar(50) NOT NULL, updated_date datetime DEFAULT NULL, updated_by varchar(50) DEFAULT NULL, primary key(record_id));");
 
         // We always want the basic tables when we do account_record_id lookups (e.g. for custom fields, tags or junction)
         initDb("drop table if exists bundles; create table bundles(record_id int(11) unsigned not null auto_increment, id char(36) not null, " +
@@ -162,4 +163,11 @@ public abstract class DBTestingHelper {
     public abstract void start() throws IOException;
 
     public abstract void stop();
+
+    private synchronized void createInstanceIfNull() {
+        if (dbiInstance == null) {
+            final String dbiString = getJdbcConnectionString();
+            dbiInstance = new DBIProvider(dbiString, USERNAME, PASSWORD).get();
+        }
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/KillbillTestSuite.java b/util/src/test/java/com/ning/billing/KillbillTestSuite.java
index 667937e..8d7d131 100644
--- a/util/src/test/java/com/ning/billing/KillbillTestSuite.java
+++ b/util/src/test/java/com/ning/billing/KillbillTestSuite.java
@@ -40,7 +40,7 @@ public class KillbillTestSuite {
 
     private boolean hasFailed = false;
 
-    private Clock clock = new ClockMock();
+    protected Clock clock = new ClockMock();
 
     protected final InternalCallContext internalCallContext = new InternalCallContext(InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID, 1687L, UUID.randomUUID(),
                                                                                       UUID.randomUUID().toString(), CallOrigin.TEST,
@@ -59,8 +59,8 @@ public class KillbillTestSuite {
     public void endTestSuite(final Method method, final ITestResult result) throws Exception {
         log.info("***************************************************************************************************");
         log.info("***   Ending test {}:{} {} ({} s.)", new Object[]{method.getDeclaringClass().getName(), method.getName(),
-                                                                    result.isSuccess() ? "SUCCESS" : "!!! FAILURE !!!",
-                                                                    (result.getEndMillis() - result.getStartMillis()) / 1000});
+                result.isSuccess() ? "SUCCESS" : "!!! FAILURE !!!",
+                (result.getEndMillis() - result.getStartMillis()) / 1000});
         log.info("***************************************************************************************************");
         if (!hasFailed && !result.isSuccess()) {
             hasFailed = true;
diff --git a/util/src/test/java/com/ning/billing/mock/glue/MockNonEntityDaoModule.java b/util/src/test/java/com/ning/billing/mock/glue/MockNonEntityDaoModule.java
new file mode 100644
index 0000000..4f230e7
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/glue/MockNonEntityDaoModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.mock.glue;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.dao.MockNonEntityDao;
+import com.ning.billing.util.cache.CacheController;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.dao.TableName;
+
+import com.google.inject.AbstractModule;
+
+public class MockNonEntityDaoModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        bind(NonEntityDao.class).to(MockNonEntityDao.class);
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
index d24059a..d1b419d 100644
--- a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
+++ b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
@@ -38,10 +38,13 @@ import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.glue.AuditModule;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.tag.DescriptiveTag;
@@ -53,7 +56,7 @@ import com.ning.billing.util.tag.dao.TagModelDao;
 
 import com.google.inject.Inject;
 
-@Guice(modules = {TagStoreModule.class, AuditModule.class, MockEntitlementModule.class, ClockModule.class, BusModule.class, MockDbHelperModule.class})
+@Guice(modules = {TagStoreModule.class, CacheModule.class, AuditModule.class, MockEntitlementModule.class, ClockModule.class, BusModule.class, MockDbHelperModule.class, NonEntityDaoModule.class})
 public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
 
     @Inject
diff --git a/util/src/test/java/com/ning/billing/util/bus/TestPersistentEventBus.java b/util/src/test/java/com/ning/billing/util/bus/TestPersistentEventBus.java
index 6d56561..abd8339 100644
--- a/util/src/test/java/com/ning/billing/util/bus/TestPersistentEventBus.java
+++ b/util/src/test/java/com/ning/billing/util/bus/TestPersistentEventBus.java
@@ -29,6 +29,8 @@ import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.glue.BusModule;
 import com.ning.billing.util.glue.BusModule.BusType;
+import com.ning.billing.util.glue.CacheModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 
 import com.google.inject.AbstractModule;
 
@@ -54,6 +56,8 @@ public class TestPersistentEventBus extends TestEventBusBase {
                 bind(IDBI.class).toInstance(dbi);
             }
             install(new BusModule(BusType.PERSISTENT));
+            install(new NonEntityDaoModule());
+            install(new CacheModule());
         }
     }
 
diff --git a/util/src/test/java/com/ning/billing/util/cache/TestCache.java b/util/src/test/java/com/ning/billing/util/cache/TestCache.java
new file mode 100644
index 0000000..1fcbf39
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/cache/TestCache.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.cache;
+
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.testng.Assert;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.mock.glue.MockDbHelperModule;
+import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
+import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
+import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
+import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
+import com.ning.billing.util.glue.CacheModule;
+import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
+import com.ning.billing.util.tag.dao.TagModelDao;
+import com.ning.billing.util.tag.dao.TagSqlDao;
+
+@Guice(modules = {ClockModule.class, CacheModule.class, MockDbHelperModule.class, NonEntityDaoModule.class } )
+public class TestCache extends UtilTestSuiteWithEmbeddedDB {
+
+    @Inject
+    private CacheControllerDispatcher controlCacheDispatcher;
+
+    @Inject
+    private NonEntityDao nonEntityDao;
+
+    private  EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
+
+
+    private void insertTag(final TagModelDao modelDao) {
+        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+            @Override
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                entitySqlDaoWrapperFactory.become(TagSqlDao.class).create(modelDao, internalCallContext);
+                return null;
+            }
+        });
+    }
+
+    private Long getTagRecordId(final UUID tagId) {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Long>() {
+            @Override
+            public Long inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                return entitySqlDaoWrapperFactory.become(TagSqlDao.class).getRecordId(tagId.toString(), internalCallContext);
+            }
+        });
+    }
+
+    private int getCacheSize() {
+        final CacheController<Object, Object> cache = controlCacheDispatcher.getCacheController(CacheType.RECORD_ID);
+        return cache != null ? cache.size() : 0;
+    }
+
+    private Long retrieveRecordIdFromCache(UUID tagId) {
+        final CacheController<Object, Object> cache = controlCacheDispatcher.getCacheController(CacheType.RECORD_ID);
+        Object result = null;
+        if (cache != null) {
+            result =  cache.get(tagId.toString(), ObjectType.TAG);
+        }
+        return (Long) result;
+    }
+
+    @Test(groups = "slow")
+    public void testCacheRecordId() throws Exception {
+
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(getDBI(), clock, controlCacheDispatcher, nonEntityDao);
+        final TagModelDao tag = new TagModelDao(clock.getUTCNow(), UUID.randomUUID(), UUID.randomUUID(), ObjectType.TAG);
+
+        // Verify we start with nothing in the cache
+        Assert.assertEquals(getCacheSize(), 0);
+        insertTag(tag);
+
+        // Verify we still have nothing after insert in the cache
+        Assert.assertEquals(getCacheSize(), 0);
+
+        final Long tagRecordId = getTagRecordId(tag.getId());
+        // Verify we now have something  in the cache
+        Assert.assertEquals(getCacheSize(), 1);
+
+        final Long recordIdFromCache = retrieveRecordIdFromCache(tag.getId());
+        Assert.assertNotNull(recordIdFromCache);
+
+        Assert.assertEquals(recordIdFromCache, new Long(1));
+        Assert.assertEquals(tagRecordId, new Long(1));
+
+        Assert.assertEquals(getCacheSize(), 1);
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java b/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java
index e62e51f..b3d9e4e 100644
--- a/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java
+++ b/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java
@@ -27,15 +27,22 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 
 public class TestInternalCallContextFactory extends UtilTestSuiteWithEmbeddedDB {
 
     private InternalCallContextFactory internalCallContextFactory;
+    private CacheControllerDispatcher cacheControllerDispatcher;
+    private NonEntityDao nonEntityDao;
 
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
-        internalCallContextFactory = new InternalCallContextFactory(getDBI(), new ClockMock());
+        cacheControllerDispatcher =  new CacheControllerDispatcher();
+        nonEntityDao = new DefaultNonEntityDao(getDBI());
+        internalCallContextFactory = new InternalCallContextFactory(new ClockMock(), nonEntityDao, cacheControllerDispatcher);
     }
 
     @Test(groups = "slow")
@@ -83,7 +90,7 @@ public class TestInternalCallContextFactory extends UtilTestSuiteWithEmbeddedDB 
             public Void withHandle(final Handle handle) throws Exception {
                 // Note: we always create an accounts table, see MysqlTestingHelper
                 handle.execute("insert into accounts (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
-                        accountRecordId, accountId.toString(), "yo@t.com", "toto", 4, false, new Date(), "i", new Date(), "j");
+                               accountRecordId, accountId.toString(), "yo@t.com", "toto", 4, false, new Date(), "i", new Date(), "j");
                 return null;
             }
         });
diff --git a/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java b/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
index 76661c2..bff019c 100644
--- a/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
+++ b/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
@@ -29,12 +29,15 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.customfield.StringCustomField;
 import com.ning.billing.util.customfield.dao.DefaultCustomFieldDao;
 import com.ning.billing.util.customfield.dao.CustomFieldDao;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.collect.ImmutableList;
 
@@ -42,10 +45,13 @@ public class TestDefaultCustomFieldUserApi extends UtilTestSuiteWithEmbeddedDB {
 
     private DefaultCustomFieldUserApi customFieldUserApi;
 
+    private CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
+
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
-        final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(getDBI(), new ClockMock());
-        final CustomFieldDao customFieldDao = new DefaultCustomFieldDao(getDBI());
+        final NonEntityDao nonEntityDao = new DefaultNonEntityDao(getDBI());
+        final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(new ClockMock(), nonEntityDao, controllerDispatcher);
+        final CustomFieldDao customFieldDao = new DefaultCustomFieldDao(getDBI(), clock, controllerDispatcher, nonEntityDao);
         customFieldUserApi = new DefaultCustomFieldUserApi(internalCallContextFactory, customFieldDao);
     }
 
diff --git a/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java b/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
index da7a8b7..6d0a494 100644
--- a/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
+++ b/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
@@ -28,9 +28,12 @@ import org.testng.annotations.Test;
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
 import com.ning.billing.util.api.CustomFieldApiException;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.customfield.dao.CustomFieldDao;
 import com.ning.billing.util.customfield.dao.CustomFieldModelDao;
 import com.ning.billing.util.customfield.dao.DefaultCustomFieldDao;
+import com.ning.billing.util.dao.DefaultNonEntityDao;
+import com.ning.billing.util.dao.NonEntityDao;
 
 import static org.testng.Assert.fail;
 
@@ -39,11 +42,14 @@ public class TestFieldStore extends UtilTestSuiteWithEmbeddedDB {
     private final Logger log = LoggerFactory.getLogger(TestFieldStore.class);
     private CustomFieldDao customFieldDao;
 
+    private CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
+
     @BeforeClass(groups = "slow")
     protected void setup() throws IOException {
         try {
             final IDBI dbi = getDBI();
-            customFieldDao = new DefaultCustomFieldDao(dbi);
+            final NonEntityDao nonEntityDao = new DefaultNonEntityDao(dbi);
+            customFieldDao = new DefaultCustomFieldDao(dbi, clock, controllerDispatcher, nonEntityDao);
         } catch (Throwable t) {
             log.error("Setup failed", t);
             fail(t.toString());
diff --git a/util/src/test/java/com/ning/billing/util/dao/TestNonEntityDao.java b/util/src/test/java/com/ning/billing/util/dao/TestNonEntityDao.java
new file mode 100644
index 0000000..5090226
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/dao/TestNonEntityDao.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.tweak.HandleCallback;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+
+public class TestNonEntityDao extends UtilTestSuiteWithEmbeddedDB {
+
+
+    final Long tenantRecordId = 123123123L;
+    final UUID tenantId = UUID.fromString("121c59d4-0458-4038-a683-698c9a121c12");
+
+
+    final UUID accountId = UUID.fromString("a01c59d4-0458-4038-a683-698c9a121c69");
+    final Long accountRecordId = 333333L;
+
+    final UUID accountHistoryId = UUID.fromString("2b1c59d4-0458-4038-a683-698c9a121c78");
+    final Long accountHistoryRecordId = 777777L;
+
+    final UUID tagDefinitionId = UUID.fromString("e01c59d4-0458-4038-a683-698c9a121c34");
+    final Long tagDefinitionRecordId = 44444444L;
+
+    final UUID tagId = UUID.fromString("123c59d4-0458-4038-a683-698c9a121456");
+    final Long tagRecordId = 55555555L;
+
+
+    private NonEntityDao nonEntityDao;
+
+    @BeforeClass(groups = "slow")
+    public void setup() {
+        nonEntityDao = new DefaultNonEntityDao(getDBI());
+    }
+
+
+    @Test(groups = "slow")
+    public void testRetrieveRecordIdFromObject() {
+
+        insertAccount();
+
+        final Long resultRecordId = nonEntityDao.retrieveRecordIdFromObject(accountId, ObjectType.ACCOUNT, null);
+        Assert.assertEquals(resultRecordId, accountRecordId);
+    }
+
+    @Test(groups = "slow")
+    public void testRetrieveAccountRecordIdFromAccountObject() {
+
+        insertAccount();
+
+        final Long resultAccountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(accountId, ObjectType.ACCOUNT, null);
+        Assert.assertEquals(resultAccountRecordId, accountRecordId);
+    }
+
+
+    @Test(groups = "slow")
+    public void testRetrieveAccountRecordIdFromTagDefinitionObject() {
+
+        insertTagDefinition();
+
+        final Long resultAccountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(tagDefinitionId, ObjectType.TAG_DEFINITION, null);
+        Assert.assertEquals(resultAccountRecordId, null);
+    }
+
+    // Not Tag_definition or account which are special
+    @Test(groups = "slow")
+    public void testRetrieveAccountRecordIdFromOtherObject() {
+
+        insertTag();
+
+        final Long resultAccountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(tagId, ObjectType.TAG, null);
+        Assert.assertEquals(resultAccountRecordId, accountRecordId);
+    }
+
+    @Test(groups = "slow")
+    public void testRetrieveTenantRecordIdFromObject() {
+
+        insertAccount();
+
+        final Long resultTenantRecordId = nonEntityDao.retrieveTenantRecordIdFromObject(accountId, ObjectType.ACCOUNT,null);
+        Assert.assertEquals(resultTenantRecordId, tenantRecordId);
+    }
+
+    @Test(groups = "slow")
+    public void testRetrieveTenantRecordIdFromTenantObject() {
+
+        insertTenant();
+
+        final Long resultTenantRecordId = nonEntityDao.retrieveTenantRecordIdFromObject(tenantId, ObjectType.TENANT, null);
+        Assert.assertEquals(resultTenantRecordId, tenantRecordId);
+    }
+
+    /*
+    @Test(groups = "slow")
+    public void testRetrieveTenantRecordIdFromTenantObject() {
+
+        insertTenant();
+
+        final Long resultTenantRecordId = nonEntityDao.retrieveLastHistoryRecordIdFromTransaction();
+        Assert.assertEquals(resultTenantRecordId, tenantRecordId);
+    }
+*/
+
+    private void insertAccount() {
+        getDBI().withHandle(new HandleCallback<Void>() {
+            @Override
+            public Void withHandle(final Handle handle) throws Exception {
+                // Note: we always create an accounts table, see MysqlTestingHelper
+                handle.execute("insert into accounts (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by, tenant_record_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+                               accountRecordId, accountId.toString(), "zozo@tt.com", "zozo", 4, false, new Date(), "i", new Date(), "j", tenantRecordId);
+                return null;
+            }
+        });
+    }
+
+    private void insertHistoryAccount() {
+        getDBI().withHandle(new HandleCallback<Void>() {
+            @Override
+            public Void withHandle(final Handle handle) throws Exception {
+                // Note: we always create an accounts table, see MysqlTestingHelper
+                handle.execute("insert into account_history (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by, tenant_record_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+                               accountRecordId, accountId.toString(), "zozo@tt.com", "zozo", 4, false, new Date(), "i", new Date(), "j", tenantRecordId);
+                return null;
+            }
+        });
+    }
+
+
+    private void insertTagDefinition() {
+        getDBI().withHandle(new HandleCallback<Void>() {
+            @Override
+            public Void withHandle(final Handle handle) throws Exception {
+                // Note: we always create an accounts table, see MysqlTestingHelper
+                handle.execute("insert into tag_definitions (record_id, id, name, description, is_active, created_date, created_by, updated_date, updated_by, tenant_record_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+                               tagDefinitionRecordId, tagDefinitionId.toString(), "tagdef", "nothing", 1, new Date(), "i", new Date(), "j", 0);
+                return null;
+            }
+        });
+    }
+
+    private void insertTag() {
+        getDBI().withHandle(new HandleCallback<Void>() {
+            @Override
+            public Void withHandle(final Handle handle) throws Exception {
+                // Note: we always create an accounts table, see MysqlTestingHelper
+                handle.execute("insert into tags (record_id, id, tag_definition_id, object_id, object_type, is_active, created_date, created_by, updated_date, updated_by, account_record_id, tenant_record_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+                               tagRecordId, tagId.toString(), tagDefinitionId.toString(), accountId.toString(), "ACCOUNT", 1, new Date(), "i", new Date(), "j", accountRecordId, 0);
+                return null;
+            }
+        });
+    }
+
+    private void insertTenant() {
+        getDBI().withHandle(new HandleCallback<Void>() {
+            @Override
+            public Void withHandle(final Handle handle) throws Exception {
+                // Note: we always create an accounts table, see MysqlTestingHelper
+                handle.execute("insert into tenants (record_id, id, external_key, api_key, api_secret, api_salt, created_date, created_by, updated_date, updated_by) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+                               tenantRecordId, tenantId.toString(), "foo",  "key", "secret", "salt", new Date(), "i", new Date(), "j");
+                return null;
+            }
+        });
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
index b0f4e74..79dbb01 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
@@ -34,12 +34,16 @@ import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
 import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
+import com.ning.billing.util.glue.CacheModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.io.IOUtils;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
 import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
@@ -56,7 +60,7 @@ import static com.jayway.awaitility.Awaitility.await;
 import static java.util.concurrent.TimeUnit.MINUTES;
 import static org.testng.Assert.assertEquals;
 
-@Guice(modules = TestNotificationQueue.TestNotificationQueueModule.class)
+@Guice(modules = {TestNotificationQueue.TestNotificationQueueModule.class, CacheModule.class, NonEntityDaoModule.class})
 public class TestNotificationQueue extends UtilTestSuiteWithEmbeddedDB {
 
     private final Logger log = LoggerFactory.getLogger(TestNotificationQueue.class);
@@ -70,7 +74,14 @@ public class TestNotificationQueue extends UtilTestSuiteWithEmbeddedDB {
     private Clock clock;
 
     @Inject
-    NotificationQueueService queueService;
+    private NotificationQueueService queueService;
+
+    @Inject
+    private CacheControllerDispatcher controllerDispatcher;
+
+    @Inject
+    private NonEntityDao nonEntityDao;
+
 
     private int eventsReceived;
 
@@ -105,7 +116,7 @@ public class TestNotificationQueue extends UtilTestSuiteWithEmbeddedDB {
     public void setup() throws Exception {
         final String testDdl = IOUtils.toString(NotificationSqlDao.class.getResourceAsStream("/com/ning/billing/util/ddl_test.sql"));
         helper.initDb(testDdl);
-        entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi);
+        entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao);
     }
 
     @BeforeTest(groups = "slow")
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDao.java
index 548a65a..fb2cac3 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDao.java
@@ -36,7 +36,9 @@ import com.ning.billing.util.bus.InMemoryBusModule;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.events.BusInternalEvent;
 import com.ning.billing.util.events.TagInternalEvent;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.tag.ControlTagType;
@@ -48,7 +50,7 @@ import com.google.inject.Inject;
 
 import static org.testng.Assert.assertEquals;
 
-@Guice(modules = {TagStoreModule.class, ClockModule.class, InMemoryBusModule.class, MockDbHelperModule.class})
+@Guice(modules = {TagStoreModule.class, CacheModule.class, ClockModule.class, InMemoryBusModule.class, MockDbHelperModule.class, NonEntityDaoModule.class})
 public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
 
     @Inject
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDefinitionDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDefinitionDao.java
index 46fe94c..8287661 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDefinitionDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDefinitionDao.java
@@ -34,14 +34,16 @@ import com.ning.billing.util.bus.InMemoryBusModule;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.events.BusInternalEvent;
 import com.ning.billing.util.events.TagDefinitionInternalEvent;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 
 import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
 
-@Guice(modules = {TagStoreModule.class, ClockModule.class, InMemoryBusModule.class, MockDbHelperModule.class})
+@Guice(modules = {TagStoreModule.class, CacheModule.class, ClockModule.class, InMemoryBusModule.class, MockDbHelperModule.class, NonEntityDaoModule.class})
 public class TestDefaultTagDefinitionDao extends UtilTestSuiteWithEmbeddedDB {
 
     @Inject
diff --git a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
index cd218de..29b76c0 100644
--- a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
+++ b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
@@ -36,7 +36,9 @@ import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.tag.dao.TagDao;
@@ -53,7 +55,7 @@ import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
 @Test(groups = {"slow"})
-@Guice(modules = {TagStoreModule.class, ClockModule.class, BusModule.class, MockDbHelperModule.class})
+@Guice(modules = {TagStoreModule.class, ClockModule.class, BusModule.class, CacheModule.class, MockDbHelperModule.class, NonEntityDaoModule.class})
 public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
 
     @Inject