killbill-memoizeit
Changes
server/src/main/resources/ehcache.xml 68(+52 -16)
util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java 86(+73 -13)
util/src/main/resources/ehcache.xml 70(+53 -17)
Details
diff --git a/account/src/test/java/com/ning/billing/account/AccountTestSuiteWithEmbeddedDB.java b/account/src/test/java/com/ning/billing/account/AccountTestSuiteWithEmbeddedDB.java
index 74df794..f1dff1a 100644
--- a/account/src/test/java/com/ning/billing/account/AccountTestSuiteWithEmbeddedDB.java
+++ b/account/src/test/java/com/ning/billing/account/AccountTestSuiteWithEmbeddedDB.java
@@ -74,6 +74,7 @@ public abstract class AccountTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
super.beforeMethod();
+ controllerDispatcher.clearAll();
bus.start();
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index 12bc382..457b626 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -85,6 +85,7 @@ import com.ning.billing.payment.api.TestPaymentMethodPluginBase;
import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
import com.ning.billing.util.api.RecordIdApi;
import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
import com.ning.billing.util.config.OSGIConfig;
import com.ning.billing.util.svcapi.account.AccountInternalApi;
import com.ning.billing.util.svcapi.junction.BlockingInternalApi;
@@ -205,6 +206,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
@Inject
protected RecordIdApi recordIdApi;
+ @javax.inject.Inject
+ protected CacheControllerDispatcher controlCacheDispatcher;
+
protected TestApiListener busHandler;
private boolean isListenerFailed;
@@ -256,6 +260,8 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
log.warn("\n");
log.warn("RESET TEST FRAMEWORK\n\n");
+ controlCacheDispatcher.clearAll();
+
clock.resetDeltaFromReality();
resetTestListenerStatus();
busHandler.reset();
diff --git a/invoice/src/test/java/com/ning/billing/invoice/InvoiceTestSuiteWithEmbeddedDB.java b/invoice/src/test/java/com/ning/billing/invoice/InvoiceTestSuiteWithEmbeddedDB.java
index a1f3bfb..ef2d32f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/InvoiceTestSuiteWithEmbeddedDB.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/InvoiceTestSuiteWithEmbeddedDB.java
@@ -121,6 +121,7 @@ public abstract class InvoiceTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
super.beforeMethod();
+ controllerDispatcher.clearAll();
bus.start();
restartInvoiceService(invoiceService);
}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
index 7eeca11..9324e71 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
@@ -97,6 +97,7 @@ public abstract class OverdueTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
super.beforeMethod();
+ cacheControllerDispatcher.clearAll();
bus.register(listener);
bus.start();
server/src/main/resources/ehcache.xml 68(+52 -16)
diff --git a/server/src/main/resources/ehcache.xml b/server/src/main/resources/ehcache.xml
index ce3e135..07e2a73 100644
--- a/server/src/main/resources/ehcache.xml
+++ b/server/src/main/resources/ehcache.xml
@@ -17,17 +17,17 @@
-->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="ehcache.xsd" >
+ xsi:noNamespaceSchemaLocation="ehcache.xsd">
- <defaultCache
- maxElementsInMemory="0"
- maxElementsOnDisk="0"
- eternal="false"
- timeToIdleSeconds="0"
- timeToLiveSeconds="0"
- overflowToDisk="false"
- statistics="true"
- />
+ <defaultCache
+ maxElementsInMemory="0"
+ maxElementsOnDisk="0"
+ eternal="false"
+ timeToIdleSeconds="0"
+ timeToLiveSeconds="0"
+ overflowToDisk="false"
+ statistics="true"
+ />
<cache name="record-id"
maxElementsInMemory="100000"
@@ -35,10 +35,12 @@
eternal="true"
overflowToDisk="false"
diskPersistent="false"
- memoryStoreEvictionPolicy="LFU">
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
<cacheEventListenerFactory
class="com.ning.billing.util.cache.ExpirationListenerFactory"
- properties="" />
+ properties=""/>
</cache>
<cache name="tenant-record-id"
@@ -47,10 +49,12 @@
eternal="true"
overflowToDisk="false"
diskPersistent="false"
- memoryStoreEvictionPolicy="LFU">
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
<cacheEventListenerFactory
class="com.ning.billing.util.cache.ExpirationListenerFactory"
- properties="" />
+ properties=""/>
</cache>
<cache name="account-record-id"
@@ -59,10 +63,42 @@
eternal="true"
overflowToDisk="false"
diskPersistent="false"
- memoryStoreEvictionPolicy="LFU">
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
<cacheEventListenerFactory
class="com.ning.billing.util.cache.ExpirationListenerFactory"
- properties="" />
+ properties=""/>
+ </cache>
+
+ <cache name="audit-log"
+ maxElementsInMemory="500000"
+ maxElementsOnDisk="0"
+ timeToIdleSeconds="600"
+ timeToLiveSeconds="600"
+ overflowToDisk="false"
+ diskPersistent="false"
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
+ <cacheEventListenerFactory
+ class="com.ning.billing.util.cache.ExpirationListenerFactory"
+ properties=""/>
+ </cache>
+
+ <cache name="audit-log-via-history"
+ maxElementsInMemory="500000"
+ maxElementsOnDisk="0"
+ timeToIdleSeconds="600"
+ timeToLiveSeconds="600"
+ overflowToDisk="false"
+ diskPersistent="false"
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
+ <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 62e7f91..900b676 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -58,6 +58,7 @@ import com.ning.billing.server.listeners.KillbillGuiceListener;
import com.ning.billing.server.modules.KillbillServerModule;
import com.ning.billing.tenant.glue.TenantModule;
import com.ning.billing.usage.glue.UsageModule;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
import com.ning.billing.util.config.PaymentConfig;
import com.ning.billing.util.email.EmailModule;
import com.ning.billing.util.email.templates.TemplateModule;
@@ -94,6 +95,9 @@ public class TestJaxrsBase extends KillbillClient {
@Inject
protected OSGIServiceRegistration<Servlet> servletRouter;
+ @Inject
+ protected CacheControllerDispatcher cacheControllerDispatcher;
+
protected static TestKillbillGuiceListener listener;
private HttpServer server;
@@ -219,6 +223,7 @@ public class TestJaxrsBase extends KillbillClient {
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
super.beforeMethod();
+ cacheControllerDispatcher.clearAll();
busHandler.reset();
clock.resetDeltaFromReality();
clock.setDay(new LocalDate(2012, 8, 25));
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 8f353f8..ac06a5a 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,7 +33,6 @@ import com.ning.billing.jaxrs.TestJaxrsBase;
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;
@@ -51,8 +50,7 @@ public class TestKillbillJdbcRealm extends TestJaxrsBase {
super.beforeMethod();
// Create the tenant
- final CacheControllerDispatcher controllerDispatcher = new CacheControllerDispatcher();
- final DefaultTenantDao tenantDao = new DefaultTenantDao(getDBI(), clock, controllerDispatcher, new DefaultNonEntityDao(getDBI()));
+ final DefaultTenantDao tenantDao = new DefaultTenantDao(getDBI(), clock, cacheControllerDispatcher, 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/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java b/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
index afd769d..a4ae781 100644
--- a/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
+++ b/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
@@ -26,22 +26,28 @@ import org.skife.jdbi.v2.IDBI;
import com.ning.billing.util.api.AuditLevel;
import com.ning.billing.util.audit.AuditLog;
import com.ning.billing.util.audit.ChangeType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.dao.AuditSqlDao;
+import com.ning.billing.util.clock.Clock;
+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.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.google.common.collect.ImmutableList;
public class DefaultAuditDao implements AuditDao {
private final NonEntitySqlDao nonEntitySqlDao;
- private final AuditSqlDao auditSqlDao;
+ private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
@Inject
- public DefaultAuditDao(final IDBI dbi) {
+ public DefaultAuditDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
this.nonEntitySqlDao = dbi.onDemand(NonEntitySqlDao.class);
- this.auditSqlDao = dbi.onDemand(AuditSqlDao.class);
+ this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
}
@Override
@@ -69,15 +75,27 @@ public class DefaultAuditDao implements AuditDao {
}
final Long targetRecordId = nonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName());
- final List<AuditLog> allAuditLogs = auditSqlDao.getAuditLogsViaHistoryForTargetRecordId(historyTableName,
- historyTableName.getTableName().toLowerCase(),
- targetRecordId,
- context);
+ final List<AuditLog> allAuditLogs = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AuditLog>>() {
+ @Override
+ public List<AuditLog> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+ return entitySqlDaoWrapperFactory.become(EntitySqlDao.class).getAuditLogsViaHistoryForTargetRecordId(historyTableName,
+ historyTableName.getTableName().toLowerCase(),
+ targetRecordId,
+ context);
+ }
+ });
return buildAuditLogs(auditLevel, allAuditLogs);
}
private List<AuditLog> getAuditLogsForRecordId(final TableName tableName, final Long targetRecordId, final AuditLevel auditLevel, final InternalTenantContext context) {
- final List<AuditLog> allAuditLogs = auditSqlDao.getAuditLogsForTargetRecordId(tableName, targetRecordId, context);
+ final List<AuditLog> allAuditLogs = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AuditLog>>() {
+ @Override
+ public List<AuditLog> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+ return entitySqlDaoWrapperFactory.become(EntitySqlDao.class).getAuditLogsForTargetRecordId(tableName,
+ targetRecordId,
+ context);
+ }
+ });
return buildAuditLogs(auditLevel, allAuditLogs);
}
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
index 9bc5a75..b4a044f 100644
--- a/util/src/main/java/com/ning/billing/util/cache/AccountRecordIdCacheLoader.java
+++ b/util/src/main/java/com/ning/billing/util/cache/AccountRecordIdCacheLoader.java
@@ -16,23 +16,20 @@
package com.ning.billing.util.cache;
-import java.util.List;
-import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
+import javax.inject.Singleton;
-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;
+@Singleton
public class AccountRecordIdCacheLoader extends BaseCacheLoader implements CacheLoader {
@Inject
@@ -41,22 +38,24 @@ public class AccountRecordIdCacheLoader extends BaseCacheLoader implements Cache
}
@Override
- public Object load(final Object key, final Object argument) {
+ public CacheType getCacheType() {
+ return CacheType.ACCOUNT_RECORD_ID;
+ }
+ @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");
-
+ throw new IllegalArgumentException("Unexpected key type of " + key.getClass().getName());
+ }
+ if (!(argument instanceof CacheLoaderArgument)) {
+ throw new IllegalArgumentException("Unexpected key type of " + argument.getClass().getName());
}
+
final String objectId = (String) key;
- final ObjectType objectType = (ObjectType) argument;
- Long value = nonEntityDao.retrieveAccountRecordIdFromObject(UUID.fromString(objectId), objectType, null);
- return value;
+ final ObjectType objectType = ((CacheLoaderArgument) argument).getObjectType();
+
+ return nonEntityDao.retrieveAccountRecordIdFromObject(UUID.fromString(objectId), objectType, null);
}
}
diff --git a/util/src/main/java/com/ning/billing/util/cache/AuditLogCacheLoader.java b/util/src/main/java/com/ning/billing/util/cache/AuditLogCacheLoader.java
new file mode 100644
index 0000000..810ab91
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/AuditLogCacheLoader.java
@@ -0,0 +1,66 @@
+/*
+ * 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 javax.inject.Singleton;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.dao.AuditSqlDao;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.dao.TableName;
+
+import net.sf.ehcache.loader.CacheLoader;
+
+@Singleton
+public class AuditLogCacheLoader extends BaseCacheLoader implements CacheLoader {
+
+ private final AuditSqlDao auditSqlDao;
+
+ @Inject
+ public AuditLogCacheLoader(final IDBI dbi, final NonEntityDao nonEntityDao) {
+ super(dbi, nonEntityDao);
+ this.auditSqlDao = dbi.onDemand(AuditSqlDao.class);
+ }
+
+ @Override
+ public CacheType getCacheType() {
+ return CacheType.AUDIT_LOG;
+ }
+
+ @Override
+ public Object load(final Object key, final Object argument) {
+ checkCacheLoaderStatus();
+
+ if (!(key instanceof String)) {
+ throw new IllegalArgumentException("Unexpected key type of " + key.getClass().getName());
+ }
+ if (!(argument instanceof CacheLoaderArgument)) {
+ throw new IllegalArgumentException("Unexpected key type of " + argument.getClass().getName());
+ }
+
+ final Object[] args = ((CacheLoaderArgument) argument).getArgs();
+ final TableName tableName = (TableName) args[0];
+ final Long targetRecordId = (Long) args[1];
+ final InternalTenantContext internalTenantContext = (InternalTenantContext) args[2];
+
+ return auditSqlDao.getAuditLogsForTargetRecordId(tableName, targetRecordId, internalTenantContext);
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/AuditLogViaHistoryCacheLoader.java b/util/src/main/java/com/ning/billing/util/cache/AuditLogViaHistoryCacheLoader.java
new file mode 100644
index 0000000..91bb2fe
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/AuditLogViaHistoryCacheLoader.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 javax.inject.Singleton;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.dao.AuditSqlDao;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.dao.TableName;
+
+import net.sf.ehcache.loader.CacheLoader;
+
+@Singleton
+public class AuditLogViaHistoryCacheLoader extends BaseCacheLoader implements CacheLoader {
+
+ private final AuditSqlDao auditSqlDao;
+
+ @Inject
+ public AuditLogViaHistoryCacheLoader(final IDBI dbi, final NonEntityDao nonEntityDao) {
+ super(dbi, nonEntityDao);
+ this.auditSqlDao = dbi.onDemand(AuditSqlDao.class);
+ }
+
+ @Override
+ public CacheType getCacheType() {
+ return CacheType.AUDIT_LOG_VIA_HISTORY;
+ }
+
+ @Override
+ public Object load(final Object key, final Object argument) {
+ checkCacheLoaderStatus();
+
+ if (!(key instanceof String)) {
+ throw new IllegalArgumentException("Unexpected key type of " + key.getClass().getName());
+ }
+ if (!(argument instanceof CacheLoaderArgument)) {
+ throw new IllegalArgumentException("Unexpected key type of " + argument.getClass().getName());
+ }
+
+ final Object[] args = ((CacheLoaderArgument) argument).getArgs();
+ final TableName tableName = (TableName) args[0];
+ final String historyTableName = (String) args[1];
+ final Long targetRecordId = (Long) args[2];
+ final InternalTenantContext internalTenantContext = (InternalTenantContext) args[3];
+
+ return auditSqlDao.getAuditLogsViaHistoryForTargetRecordId(tableName, historyTableName, targetRecordId, internalTenantContext);
+ }
+}
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
index 855fdef..84ff464 100644
--- a/util/src/main/java/com/ning/billing/util/cache/BaseCacheLoader.java
+++ b/util/src/main/java/com/ning/billing/util/cache/BaseCacheLoader.java
@@ -23,6 +23,7 @@ import javax.inject.Inject;
import org.skife.jdbi.v2.IDBI;
+import com.ning.billing.util.cache.Cachable.CacheType;
import com.ning.billing.util.dao.NonEntityDao;
import net.sf.ehcache.CacheException;
@@ -44,10 +45,11 @@ public abstract class BaseCacheLoader implements CacheLoader {
this.cacheLoaderStatus = Status.STATUS_UNINITIALISED;
}
+ public abstract CacheType getCacheType();
+
@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 ");
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
index ac9e0ee..cdd65cc 100644
--- a/util/src/main/java/com/ning/billing/util/cache/Cachable.java
+++ b/util/src/main/java/com/ning/billing/util/cache/Cachable.java
@@ -20,7 +20,6 @@ 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})
@@ -29,42 +28,41 @@ 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 final String AUDIT_LOG_CACHE_NAME = "audit-log";
+ public final String AUDIT_LOG_VIA_HISTORY_CACHE_NAME = "audit-log-via-history";
public CacheType value();
public enum CacheType {
/* Mapping from object 'id (UUID)' -> object 'recordId (Long' */
- RECORD_ID(RECORD_ID_CACHE_NAME, UUID.class, Long.class),
+ RECORD_ID(RECORD_ID_CACHE_NAME),
/* Mapping from object 'id (UUID)' -> matching account object 'accountRecordId (Long)' */
- ACCOUNT_RECORD_ID(ACCOUNT_RECORD_ID_CACHE_NAME, UUID.class, Long.class),
-
+ ACCOUNT_RECORD_ID(ACCOUNT_RECORD_ID_CACHE_NAME),
/* Mapping from object 'id (UUID)' -> matching object 'tenantRecordId (Long)' */
- TENANT_RECORD_ID(TENANT_RECORD_ID_CACHE_NAME, UUID.class, Long.class);
+ TENANT_RECORD_ID(TENANT_RECORD_ID_CACHE_NAME),
+
+ /* Mapping from object 'tableName::targetRecordId' -> matching objects 'Iterable<AuditLog>' */
+ AUDIT_LOG(AUDIT_LOG_CACHE_NAME),
+
+ /* Mapping from object 'tableName::historyTableName::targetRecordId' -> matching objects 'Iterable<AuditLog>' */
+ AUDIT_LOG_VIA_HISTORY(AUDIT_LOG_VIA_HISTORY_CACHE_NAME);
private final String cacheName;
- private final Class key;
- private final Class value;
- CacheType(final String cacheName, final Class key, final Class value) {
+ CacheType(final String cacheName) {
this.cacheName = cacheName;
- this.key = key;
- this.value = value;
- }
-
- public Class getKey() {
- return key;
}
- public Class getValue() {
- return value;
+ public String getCacheName() {
+ return cacheName;
}
public static CacheType findByName(final String input) {
- for (CacheType cur : CacheType.values()) {
- if (cur.cacheName.equals(input)) {
- return cur;
+ for (final CacheType cacheType : CacheType.values()) {
+ if (cacheType.cacheName.equals(input)) {
+ return cacheType;
}
}
return null;
diff --git a/util/src/main/java/com/ning/billing/util/cache/CachableKey.java b/util/src/main/java/com/ning/billing/util/cache/CachableKey.java
new file mode 100644
index 0000000..1ef1f50
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/CachableKey.java
@@ -0,0 +1,30 @@
+/*
+ * 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.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface CachableKey {
+
+ // Position (start at 1)
+ public int value();
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/CacheController.java b/util/src/main/java/com/ning/billing/util/cache/CacheController.java
index 4655a8c..581dd4b 100644
--- a/util/src/main/java/com/ning/billing/util/cache/CacheController.java
+++ b/util/src/main/java/com/ning/billing/util/cache/CacheController.java
@@ -16,18 +16,13 @@
package com.ning.billing.util.cache;
-import java.util.Collection;
-
-import com.ning.billing.ObjectType;
-import com.ning.billing.util.cache.Cachable.CacheType;
-
public interface CacheController<K, V> {
- public CacheType getType();
-
- public V get(K key, ObjectType objectType);
+ public V get(K key, CacheLoaderArgument objectType);
public boolean remove(K key);
public int size();
+
+ void removeAll();
}
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
index ee9b3d0..8681220 100644
--- a/util/src/main/java/com/ning/billing/util/cache/CacheControllerDispatcher.java
+++ b/util/src/main/java/com/ning/billing/util/cache/CacheControllerDispatcher.java
@@ -16,38 +16,35 @@
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;
-
+// Kill Bill generic cache dispatcher
public class CacheControllerDispatcher {
- private final Map<CacheType, CacheController<?,?>> caches;
+ private final Map<CacheType, CacheController<Object, Object>> 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);
+ public CacheControllerDispatcher(final Map<CacheType, CacheController<Object, Object>> caches) {
+ this.caches = caches;
}
// Test only
public CacheControllerDispatcher() {
- caches = new HashMap<CacheType, CacheController<?, ?>>();
+ caches = new HashMap<CacheType, CacheController<Object, Object>>();
+ }
+
+ public CacheController<Object, Object> getCacheController(final CacheType cacheType) {
+ return caches.get(cacheType);
}
- public <K,V> CacheController<K, V> getCacheController(CacheType cacheType) {
- // STEPH Not the prettiest thing..
- return CacheController.class.cast(caches.get(cacheType));
+ public void clearAll() {
+ for (final CacheController<Object, Object> cacheController : caches.values()) {
+ cacheController.removeAll();
+ }
}
}
diff --git a/util/src/main/java/com/ning/billing/util/cache/CacheControllerDispatcherProvider.java b/util/src/main/java/com/ning/billing/util/cache/CacheControllerDispatcherProvider.java
new file mode 100644
index 0000000..79a9894
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/CacheControllerDispatcherProvider.java
@@ -0,0 +1,72 @@
+/*
+ * 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.LinkedHashMap;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+import com.ning.billing.util.cache.Cachable.CacheType;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.loader.CacheLoader;
+
+// Build the abstraction layer between EhCache and Kill Bill
+public class CacheControllerDispatcherProvider implements Provider<CacheControllerDispatcher> {
+
+ private final CacheManager cacheManager;
+
+ @Inject
+ public CacheControllerDispatcherProvider(final CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ }
+
+ @Override
+ public CacheControllerDispatcher get() {
+ final Map<CacheType, CacheController<Object, Object>> cacheControllers = new LinkedHashMap<CacheType, CacheController<Object, Object>>();
+ for (final String cacheName : cacheManager.getCacheNames()) {
+ final CacheType cacheType = CacheType.findByName(cacheName);
+
+ final Collection<EhCacheBasedCacheController<Object, Object>> cacheControllersForCacheName = getCacheControllersForCacheName(cacheName);
+ // EhCache supports multiple cache loaders per type, but not Kill Bill - take the first one
+ if (cacheControllersForCacheName.size() > 0) {
+ final EhCacheBasedCacheController<Object, Object> ehCacheBasedCacheController = cacheControllersForCacheName.iterator().next();
+ cacheControllers.put(cacheType, ehCacheBasedCacheController);
+ }
+ }
+
+ return new CacheControllerDispatcher(cacheControllers);
+ }
+
+ public Collection<EhCacheBasedCacheController<Object, Object>> getCacheControllersForCacheName(final String name) {
+ final Cache cache = cacheManager.getCache(name);
+
+ // The CacheLoaders were registered in EhCacheCacheManagerProvider
+ return Collections2.transform(cache.getRegisteredCacheLoaders(), new Function<CacheLoader, EhCacheBasedCacheController<Object, Object>>() {
+ @Override
+ public EhCacheBasedCacheController<Object, Object> apply(final CacheLoader input) {
+ return new EhCacheBasedCacheController<Object, Object>(cache);
+ }
+ });
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/cache/CacheLoaderArgument.java b/util/src/main/java/com/ning/billing/util/cache/CacheLoaderArgument.java
new file mode 100644
index 0000000..11f51a0
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/cache/CacheLoaderArgument.java
@@ -0,0 +1,51 @@
+/*
+ * 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 javax.annotation.Nullable;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.callcontext.InternalTenantContext;
+
+public class CacheLoaderArgument {
+
+ private final ObjectType objectType;
+ private final Object[] args;
+ private final InternalTenantContext internalTenantContext;
+
+ public CacheLoaderArgument(final ObjectType objectType) {
+ this(objectType, new Object[]{}, null);
+ }
+
+ public CacheLoaderArgument(final ObjectType objectType, final Object[] args, @Nullable final InternalTenantContext internalTenantContext) {
+ this.objectType = objectType;
+ this.args = args;
+ this.internalTenantContext = internalTenantContext;
+ }
+
+ public ObjectType getObjectType() {
+ return objectType;
+ }
+
+ public Object[] getArgs() {
+ return args;
+ }
+
+ public InternalTenantContext getInternalTenantContext() {
+ return internalTenantContext;
+ }
+}
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
index 623f1f7..6f0a5b3 100644
--- a/util/src/main/java/com/ning/billing/util/cache/EhCacheBasedCacheController.java
+++ b/util/src/main/java/com/ning/billing/util/cache/EhCacheBasedCacheController.java
@@ -16,33 +16,20 @@
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) {
+ public EhCacheBasedCacheController(final Cache cache) {
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);
+ public V get(final K key, final CacheLoaderArgument cacheLoaderArgument) {
+ final Element element = cache.getWithLoader(key, null, cacheLoaderArgument);
if (element == null) {
return null;
}
@@ -58,4 +45,9 @@ public class EhCacheBasedCacheController<K, V> implements CacheController<K, V>
public int size() {
return cache.getSize();
}
+
+ @Override
+ public void removeAll() {
+ cache.removeAll();
+ }
}
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
index 3489753..fe9fc1f 100644
--- a/util/src/main/java/com/ning/billing/util/cache/RecordIdCacheLoader.java
+++ b/util/src/main/java/com/ning/billing/util/cache/RecordIdCacheLoader.java
@@ -19,15 +19,18 @@ package com.ning.billing.util.cache;
import java.util.UUID;
import javax.inject.Inject;
+import javax.inject.Singleton;
import org.skife.jdbi.v2.IDBI;
import com.ning.billing.ObjectType;
+import com.ning.billing.util.cache.Cachable.CacheType;
import com.ning.billing.util.dao.NonEntityDao;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.loader.CacheLoader;
+@Singleton
public class RecordIdCacheLoader extends BaseCacheLoader implements CacheLoader {
@Inject
@@ -36,22 +39,24 @@ public class RecordIdCacheLoader extends BaseCacheLoader implements CacheLoader
}
@Override
- public Object load(final Object key, final Object argument) throws CacheException {
+ public CacheType getCacheType() {
+ return CacheType.RECORD_ID;
+ }
+ @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");
-
+ throw new IllegalArgumentException("Unexpected key type of " + key.getClass().getName());
+ }
+ if (!(argument instanceof CacheLoaderArgument)) {
+ throw new IllegalArgumentException("Unexpected key type of " + argument.getClass().getName());
}
+
final String objectId = (String) key;
- final ObjectType objectType = (ObjectType) argument;
- Long value = nonEntityDao.retrieveRecordIdFromObject(UUID.fromString(objectId), objectType, null);
- return value;
+ final ObjectType objectType = ((CacheLoaderArgument) argument).getObjectType();
+
+ return nonEntityDao.retrieveRecordIdFromObject(UUID.fromString(objectId), objectType, null);
}
}
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
index d8c2eb4..c16d4de 100644
--- a/util/src/main/java/com/ning/billing/util/cache/TenantRecordIdCacheLoader.java
+++ b/util/src/main/java/com/ning/billing/util/cache/TenantRecordIdCacheLoader.java
@@ -19,15 +19,18 @@ package com.ning.billing.util.cache;
import java.util.UUID;
import javax.inject.Inject;
+import javax.inject.Singleton;
import org.skife.jdbi.v2.IDBI;
import com.ning.billing.ObjectType;
+import com.ning.billing.util.cache.Cachable.CacheType;
import com.ning.billing.util.dao.NonEntityDao;
import net.sf.ehcache.loader.CacheLoader;
-public class TenantRecordIdCacheLoader extends BaseCacheLoader implements CacheLoader {
+@Singleton
+public class TenantRecordIdCacheLoader extends BaseCacheLoader implements CacheLoader {
@Inject
public TenantRecordIdCacheLoader(final IDBI dbi, final NonEntityDao nonEntityDao) {
@@ -35,22 +38,24 @@ public class TenantRecordIdCacheLoader extends BaseCacheLoader implements Cache
}
@Override
- public Object load(final Object key, final Object argument) {
+ public CacheType getCacheType() {
+ return CacheType.TENANT_RECORD_ID;
+ }
+ @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");
-
+ throw new IllegalArgumentException("Unexpected key type of " + key.getClass().getName());
+ }
+ if (!(argument instanceof CacheLoaderArgument)) {
+ throw new IllegalArgumentException("Unexpected key type of " + argument.getClass().getName());
}
+
final String objectId = (String) key;
- final ObjectType objectType = (ObjectType) argument;
- Long value = nonEntityDao.retrieveTenantRecordIdFromObject(UUID.fromString(objectId), objectType, null);
- return value;
+ final ObjectType objectType = ((CacheLoaderArgument) argument).getObjectType();
+
+ return nonEntityDao.retrieveTenantRecordIdFromObject(UUID.fromString(objectId), objectType, null);
}
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java b/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
index 3b95a3b..fea7437 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
@@ -20,17 +20,26 @@ import java.util.List;
import org.skife.jdbi.v2.sqlobject.Bind;
import org.skife.jdbi.v2.sqlobject.BindBean;
-import org.skife.jdbi.v2.sqlobject.SqlBatch;
import org.skife.jdbi.v2.sqlobject.SqlQuery;
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
import org.skife.jdbi.v2.sqlobject.customizers.Define;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.cache.Cachable;
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.cache.CachableKey;
import com.ning.billing.util.callcontext.InternalCallContext;
import com.ning.billing.util.callcontext.InternalTenantContext;
import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+/**
+ * Note: cache invalidation has to happen for audit logs (which is tricky in the multi-nodes scenario).
+ * For now, we're using a time-based eviction strategy (see timeToIdleSeconds and timeToLiveSeconds in ehcache.xml)
+ * which is good enough: the cache will always get at least the initial CREATION audit log entry, which is the one
+ * we really care about (both for Analytics and for Kaui's endpoints). Besides, we do cache invalidation properly
+ * on our own node (see EntitySqlDaoWrapperInvocationHandler).
+ */
@EntitySqlDaoStringTemplate("/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg")
@RegisterMapper(AuditLogMapper.class)
public interface AuditSqlDao {
@@ -39,18 +48,16 @@ public interface AuditSqlDao {
public void insertAuditFromTransaction(@BindBean final EntityAudit audit,
@BindBean final InternalCallContext context);
- @SqlBatch(transactional = false)
- public void insertAuditFromTransaction(@BindBean final List<EntityAudit> audit,
- @BindBean final InternalCallContext context);
-
@SqlQuery
- public List<AuditLog> getAuditLogsForTargetRecordId(@BindBean final TableName tableName,
- @Bind("targetRecordId") final long targetRecordId,
+ @Cachable(CacheType.AUDIT_LOG)
+ public List<AuditLog> getAuditLogsForTargetRecordId(@CachableKey(1) @BindBean final TableName tableName,
+ @CachableKey(2) @Bind("targetRecordId") final long targetRecordId,
@BindBean final InternalTenantContext context);
@SqlQuery
- public List<AuditLog> getAuditLogsViaHistoryForTargetRecordId(@BindBean final TableName tableName,
- @Define("historyTableName") final String historyTableName,
- @Bind("targetRecordId") final long targetRecordId,
+ @Cachable(CacheType.AUDIT_LOG_VIA_HISTORY)
+ public List<AuditLog> getAuditLogsViaHistoryForTargetRecordId(@CachableKey(1) @BindBean final TableName historyTableName, /* Uppercased - used to find entries in audit_log table */
+ @CachableKey(2) @Define("historyTableName") final String actualHistoryTableName, /* Actual table name, used in the inner join query */
+ @CachableKey(3) @Bind("targetRecordId") final long targetRecordId,
@BindBean final InternalTenantContext context);
}
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
index dbf838a..232983e 100644
--- a/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java
@@ -25,6 +25,7 @@ import org.skife.jdbi.v2.IDBI;
import com.ning.billing.ObjectType;
import com.ning.billing.util.cache.CacheController;
+import com.ning.billing.util.cache.CacheLoaderArgument;
public class DefaultNonEntityDao implements NonEntityDao {
@@ -52,8 +53,6 @@ public class DefaultNonEntityDao implements NonEntityDao {
}
public Long retrieveAccountRecordIdFromObject(@Nullable 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) {
@@ -74,7 +73,6 @@ public class DefaultNonEntityDao implements NonEntityDao {
}, objectId, objectType, cache);
}
-
public Long retrieveTenantRecordIdFromObject(@Nullable final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
@@ -110,18 +108,16 @@ public class DefaultNonEntityDao implements NonEntityDao {
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, @Nullable final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
+ private Long withCaching(final OperationRetrieval<Long> op, @Nullable final UUID objectId, final ObjectType objectType, @Nullable final CacheController<Object, Object> cache) {
if (objectId == null) {
return null;
}
if (cache != null) {
- final Long cachedResult = (Long) cache.get(objectId.toString(), objectType);
- return cachedResult;
+ return (Long) cache.get(objectId.toString(), new CacheLoaderArgument(objectType));
}
return op.doRetrieve(objectId, objectType);
}
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 25f8e6c..14f3859 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
@@ -29,6 +29,7 @@ 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.cache.CachableKey;
import com.ning.billing.util.callcontext.InternalCallContext;
import com.ning.billing.util.callcontext.InternalTenantContext;
import com.ning.billing.util.dao.AuditSqlDao;
@@ -61,7 +62,7 @@ public interface EntitySqlDao<M extends EntityModelDao<E>, E extends Entity> ext
@SqlQuery
@Cachable(CacheType.RECORD_ID)
- public Long getRecordId(@Bind("id") final String id,
+ public Long getRecordId(@CachableKey(1) @Bind("id") final String id,
@BindBean final InternalTenantContext context);
@SqlQuery
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoStringTemplate.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoStringTemplate.java
index f96ea42..143f3bc 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoStringTemplate.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoStringTemplate.java
@@ -23,6 +23,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
import org.skife.jdbi.v2.Query;
import org.skife.jdbi.v2.SQLStatement;
@@ -75,7 +76,8 @@ public @interface EntitySqlDaoStringTemplate {
if (sqlObjectType.getGenericInterfaces()[i] instanceof ParameterizedType) {
final ParameterizedType type = (ParameterizedType) sqlObjectType.getGenericInterfaces()[i];
for (int j = 0; j < type.getActualTypeArguments().length; j++) {
- final Class modelClazz = (Class) type.getActualTypeArguments()[j];
+ final Type modelType = type.getActualTypeArguments()[j];
+ final Class modelClazz = (Class) modelType;
if (Entity.class.isAssignableFrom(modelClazz)) {
query.registerMapper(new LowerToCamelBeanMapperFactory(modelClazz));
}
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 0cd07c6..a00d894 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
@@ -25,9 +25,9 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
import org.skife.jdbi.v2.Binding;
import org.skife.jdbi.v2.StatementContext;
@@ -41,9 +41,12 @@ 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.CachableKey;
import com.ning.billing.util.cache.CacheController;
import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.cache.CacheLoaderArgument;
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.EntityAudit;
import com.ning.billing.util.dao.EntityHistoryModelDao;
@@ -51,11 +54,13 @@ 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.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
/**
* Wraps an instance of EntitySqlDao, performing extra work around each method (Sql query)
@@ -66,6 +71,8 @@ import com.google.common.collect.ImmutableList.Builder;
*/
public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, M extends EntityModelDao<E>, E extends Entity> implements InvocationHandler {
+ public static final String CACHE_KEY_SEPARATOR = "::";
+
private final Logger logger = LoggerFactory.getLogger(EntitySqlDaoWrapperInvocationHandler.class);
private final Class<S> sqlDaoClass;
@@ -169,14 +176,36 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
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);
+ // Find all arguments marked with @CachableKey
+ final Map<Integer, Object> keyPieces = new LinkedHashMap<Integer, Object>();
+ final Annotation[][] annotations = method.getParameterAnnotations();
+ for (int i = 0; i < annotations.length; i++) {
+ for (int j = 0; j < annotations[i].length; j++) {
+ final Annotation annotation = annotations[i][j];
+ if (CachableKey.class.equals(annotation.annotationType())) {
+ // CachableKey position starts at 1
+ keyPieces.put(((CachableKey) annotation).value() - 1, args[i]);
+ break;
+ }
+ }
+ }
+
+ // Build the Cache key
+ final String cacheKey = buildCacheKey(keyPieces);
+
+ final InternalTenantContext internalTenantContext = (InternalTenantContext) Iterables.find(ImmutableList.copyOf(args), new Predicate<Object>() {
+ @Override
+ public boolean apply(final Object input) {
+ return input instanceof InternalTenantContext;
+ }
+ }, null);
+ final CacheLoaderArgument cacheLoaderArgument = new CacheLoaderArgument(objectType, args, internalTenantContext);
+ result = cache.get(cacheKey, cacheLoaderArgument);
}
if (result == null) {
result = method.invoke(sqlDao, args);
@@ -198,17 +227,23 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
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())) {
+ final Type type = sqlDaoClass.getGenericInterfaces()[0];
+ if (!(type instanceof java.lang.reflect.ParameterizedType)) {
+ // AuditSqlDao for example won't extend EntitySqlDao
+ return null;
+ }
+
+ if (EntitySqlDao.class.getName().equals(((Class) ((java.lang.reflect.ParameterizedType) type).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();
+ final 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]);
+ final Class clz = ((Class) types[i]);
if (EntityModelDao.class.getName().equals(((Class) ((java.lang.reflect.ParameterizedType) clz.getGenericInterfaces()[0]).getRawType()).getName())) {
foundIndexForEntityModelDao = i;
break;
@@ -216,11 +251,11 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
}
if (foundIndexForEntityModelDao >= 0) {
- String modelClassName = ((Class) types[foundIndexForEntityModelDao]).getName();
+ final String modelClassName = ((Class) types[foundIndexForEntityModelDao]).getName();
- Class<? extends EntityModelDao<?>> clz = (Class<? extends EntityModelDao<?>>) Class.forName(modelClassName);
+ final Class<? extends EntityModelDao<?>> clz = (Class<? extends EntityModelDao<?>>) Class.forName(modelClassName);
- EntityModelDao<?> modelDao = (EntityModelDao<?>) clz.newInstance();
+ final EntityModelDao<?> modelDao = (EntityModelDao<?>) clz.newInstance();
return modelDao.getTableName().getObjectType();
}
}
@@ -272,7 +307,7 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
historyRecordId = entityRecordId;
}
- insertAudits(tableName, historyRecordId, changeType, context);
+ insertAudits(tableName, entityRecordId, historyRecordId, changeType, context);
}
private List<String> retrieveEntityIdsFromArguments(final Method method, final Object[] args) {
@@ -349,9 +384,34 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
return nonEntityDao.retrieveLastHistoryRecordIdFromTransaction(entityRecordId, entityModelDao.getHistoryTableName(), transactional);
}
- private void insertAudits(final TableName tableName, final Long historyRecordId, final ChangeType changeType, final InternalCallContext context) {
+ private void insertAudits(final TableName tableName, final Long entityRecordId, final Long historyRecordId, final ChangeType changeType, final InternalCallContext context) {
final TableName destinationTableName = Objects.firstNonNull(tableName.getHistoryTableName(), tableName);
final EntityAudit audit = new EntityAudit(destinationTableName, historyRecordId, changeType, clock.getUTCNow());
sqlDao.insertAuditFromTransaction(audit, context);
+
+ // We need to invalidate the caches. There is a small window of doom here where caches will be stale.
+ // TODO Knowledge on how the key is constructed is also in AuditSqlDao
+ if (tableName.getHistoryTableName() != null) {
+ final String key = buildCacheKey(ImmutableMap.<Integer, Object>of(0, tableName.getHistoryTableName(), 1, tableName.getHistoryTableName(), 2, entityRecordId));
+ cacheControllerDispatcher.getCacheController(CacheType.AUDIT_LOG_VIA_HISTORY).remove(key);
+ } else {
+ final String key = buildCacheKey(ImmutableMap.<Integer, Object>of(0, tableName, 1, entityRecordId));
+ cacheControllerDispatcher.getCacheController(CacheType.AUDIT_LOG).remove(key);
+ }
+ }
+
+ private String buildCacheKey(final Map<Integer, Object> keyPieces) {
+ final StringBuilder cacheKey = new StringBuilder();
+ for (int i = 0; i < keyPieces.size(); i++) {
+ // To normalize the arguments and avoid casing issues, we make all pieces of the key uppercase.
+ // Since the database engine may be case insensitive and we use arguments of the SQL method call
+ // to build the key, the key has to be case insensitive as well.
+ final String str = String.valueOf(keyPieces.get(i)).toUpperCase();
+ cacheKey.append(str);
+ if (i < keyPieces.size() - 1) {
+ cacheKey.append(CACHE_KEY_SEPARATOR);
+ }
+ }
+ return cacheKey.toString();
}
}
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
index df3c014..f8e3ec1 100644
--- a/util/src/main/java/com/ning/billing/util/glue/CacheModule.java
+++ b/util/src/main/java/com/ning/billing/util/glue/CacheModule.java
@@ -16,60 +16,34 @@
package com.ning.billing.util.glue;
-import java.util.UUID;
-
import org.skife.config.ConfigSource;
import org.skife.config.ConfigurationObjectFactory;
-import com.ning.billing.util.cache.AccountRecordIdCacheLoader;
-import com.ning.billing.util.cache.Cachable;
-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.cache.CacheControllerDispatcherProvider;
+import com.ning.billing.util.cache.EhCacheCacheManagerProvider;
import com.ning.billing.util.config.CacheConfig;
import com.google.inject.AbstractModule;
-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);
-
private final ConfigSource configSource;
public CacheModule(final ConfigSource configSource) {
this.configSource = configSource;
}
- protected void installConfig() {
- 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();
+ final CacheConfig config = new ConfigurationObjectFactory(configSource).build(CacheConfig.class);
+ bind(CacheConfig.class).toInstance(config);
- 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();
+ // EhCache specifics
+ bind(CacheManager.class).toProvider(EhCacheCacheManagerProvider.class).asEagerSingleton();
- bind(CacheControllerDispatcher.class).asEagerSingleton();
+ // Kill Bill generic cache dispatcher
+ bind(CacheControllerDispatcher.class).toProvider(CacheControllerDispatcherProvider.class).asEagerSingleton();
}
}
util/src/main/resources/ehcache.xml 70(+53 -17)
diff --git a/util/src/main/resources/ehcache.xml b/util/src/main/resources/ehcache.xml
index 684c3c8..07e2a73 100644
--- a/util/src/main/resources/ehcache.xml
+++ b/util/src/main/resources/ehcache.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- ~ Copyright 2010-2012 Ning, Inc.
+ ~ 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
@@ -17,17 +17,17 @@
-->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="ehcache.xsd" >
+ xsi:noNamespaceSchemaLocation="ehcache.xsd">
- <defaultCache
- maxElementsInMemory="0"
- maxElementsOnDisk="0"
- eternal="false"
- timeToIdleSeconds="0"
- timeToLiveSeconds="0"
- overflowToDisk="false"
- statistics="true"
- />
+ <defaultCache
+ maxElementsInMemory="0"
+ maxElementsOnDisk="0"
+ eternal="false"
+ timeToIdleSeconds="0"
+ timeToLiveSeconds="0"
+ overflowToDisk="false"
+ statistics="true"
+ />
<cache name="record-id"
maxElementsInMemory="100000"
@@ -35,10 +35,12 @@
eternal="true"
overflowToDisk="false"
diskPersistent="false"
- memoryStoreEvictionPolicy="LFU">
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
<cacheEventListenerFactory
class="com.ning.billing.util.cache.ExpirationListenerFactory"
- properties="" />
+ properties=""/>
</cache>
<cache name="tenant-record-id"
@@ -47,10 +49,12 @@
eternal="true"
overflowToDisk="false"
diskPersistent="false"
- memoryStoreEvictionPolicy="LFU">
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
<cacheEventListenerFactory
class="com.ning.billing.util.cache.ExpirationListenerFactory"
- properties="" />
+ properties=""/>
</cache>
<cache name="account-record-id"
@@ -59,10 +63,42 @@
eternal="true"
overflowToDisk="false"
diskPersistent="false"
- memoryStoreEvictionPolicy="LFU">
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
<cacheEventListenerFactory
class="com.ning.billing.util.cache.ExpirationListenerFactory"
- properties="" />
+ properties=""/>
+ </cache>
+
+ <cache name="audit-log"
+ maxElementsInMemory="500000"
+ maxElementsOnDisk="0"
+ timeToIdleSeconds="600"
+ timeToLiveSeconds="600"
+ overflowToDisk="false"
+ diskPersistent="false"
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
+ <cacheEventListenerFactory
+ class="com.ning.billing.util.cache.ExpirationListenerFactory"
+ properties=""/>
+ </cache>
+
+ <cache name="audit-log-via-history"
+ maxElementsInMemory="500000"
+ maxElementsOnDisk="0"
+ timeToIdleSeconds="600"
+ timeToLiveSeconds="600"
+ overflowToDisk="false"
+ diskPersistent="false"
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
+ <cacheEventListenerFactory
+ class="com.ning.billing.util.cache.ExpirationListenerFactory"
+ properties=""/>
</cache>
</ehcache>
diff --git a/util/src/test/java/com/ning/billing/GuicyKillbillTestWithEmbeddedDBModule.java b/util/src/test/java/com/ning/billing/GuicyKillbillTestWithEmbeddedDBModule.java
index 7f44985..c5567a1 100644
--- a/util/src/test/java/com/ning/billing/GuicyKillbillTestWithEmbeddedDBModule.java
+++ b/util/src/test/java/com/ning/billing/GuicyKillbillTestWithEmbeddedDBModule.java
@@ -27,9 +27,9 @@ import com.ning.billing.dbi.MysqlTestingHelper;
public class GuicyKillbillTestWithEmbeddedDBModule extends GuicyKillbillTestModule {
- private final static Logger log = LoggerFactory.getLogger(GuicyKillbillTestWithEmbeddedDBModule.class);
+ private static final Logger log = LoggerFactory.getLogger(GuicyKillbillTestWithEmbeddedDBModule.class);
- private static DBTestingHelper instance = getDBTestingHelper();
+ private static final DBTestingHelper instance = getDBTestingHelper();
public static synchronized DBTestingHelper getDBTestingHelper() {
if (instance == null) {
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 8ed8aa5..6fbc2a9 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,7 +38,7 @@ import com.ning.billing.util.tag.dao.TagModelDao;
public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
- private UUID tagId;
+ private TagModelDao tag;
@Test(groups = "slow")
public void testRetrieveAuditsDirectly() throws Exception {
@@ -60,11 +60,25 @@ public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
addTag();
for (final AuditLevel level : AuditLevel.values()) {
- final List<AuditLog> auditLogs = auditDao.getAuditLogsForId(TableName.TAG, tagId, level, internalCallContext);
+ final List<AuditLog> auditLogs = auditDao.getAuditLogsForId(TableName.TAG, tag.getId(), level, internalCallContext);
verifyAuditLogsForTag(auditLogs, level);
}
}
+ @Test(groups = "slow")
+ public void testVerifyAuditCachesAreCleared() throws Exception {
+ addTag();
+ final List<AuditLog> firstAuditLogs = auditDao.getAuditLogsForId(TableName.TAG, tag.getId(), AuditLevel.FULL, internalCallContext);
+ Assert.assertEquals(firstAuditLogs.size(), 1);
+ Assert.assertEquals(firstAuditLogs.get(0).getChangeType(), ChangeType.INSERT);
+
+ tagDao.deleteTag(tag.getObjectId(), tag.getObjectType(), tag.getTagDefinitionId(), internalCallContext);
+ final List<AuditLog> secondAuditLogs = auditDao.getAuditLogsForId(TableName.TAG, tag.getId(), AuditLevel.FULL, internalCallContext);
+ Assert.assertEquals(secondAuditLogs.size(), 2);
+ Assert.assertEquals(secondAuditLogs.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(secondAuditLogs.get(1).getChangeType(), ChangeType.DELETE);
+ }
+
private void addTag() throws TagDefinitionApiException, TagApiException {
// Create a tag definition
final TagDefinitionModelDao tagDefinition = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5),
@@ -75,14 +89,13 @@ public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
// Create a tag
final UUID objectId = UUID.randomUUID();
- final Tag tag = new DescriptiveTag(tagDefinition.getId(), ObjectType.ACCOUNT, objectId, clock.getUTCNow());
+ final Tag theTag = new DescriptiveTag(tagDefinition.getId(), ObjectType.ACCOUNT, objectId, clock.getUTCNow());
- tagDao.create(new TagModelDao(tag), internalCallContext);
+ tagDao.create(new TagModelDao(theTag), internalCallContext);
final List<TagModelDao> tags = tagDao.getTagsForObject(objectId, ObjectType.ACCOUNT, internalCallContext);
Assert.assertEquals(tags.size(), 1);
- final TagModelDao savedTag = tags.get(0);
- Assert.assertEquals(savedTag.getTagDefinitionId(), tagDefinition.getId());
- tagId = savedTag.getId();
+ tag = tags.get(0);
+ Assert.assertEquals(tag.getTagDefinitionId(), tagDefinition.getId());
}
private void verifyAuditLogsForTag(final List<AuditLog> auditLogs, final AuditLevel level) {
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
index 1c4c113..07680f1 100644
--- a/util/src/test/java/com/ning/billing/util/cache/TestCache.java
+++ b/util/src/test/java/com/ning/billing/util/cache/TestCache.java
@@ -18,24 +18,16 @@ 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;
@@ -72,7 +64,8 @@ public class TestCache extends UtilTestSuiteWithEmbeddedDB {
final CacheController<Object, Object> cache = controlCacheDispatcher.getCacheController(CacheType.RECORD_ID);
Object result = null;
if (cache != null) {
- result = cache.get(tagId.toString(), ObjectType.TAG);
+ // Keys are upper cased by convention
+ result = cache.get(tagId.toString().toUpperCase(), new CacheLoaderArgument(ObjectType.TAG));
}
return (Long) result;
}
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 71a03f4..1babdf5 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
@@ -87,7 +87,7 @@ public class TestNotificationQueue extends UtilTestSuiteWithEmbeddedDB {
@BeforeClass(groups = "slow")
public void beforeClass() throws Exception {
super.beforeClass();
- entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(getDBI(), clock, cacheControllerDispatcher, nonEntityDao);
+ entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(getDBI(), clock, controlCacheDispatcher, nonEntityDao);
}
@Override
diff --git a/util/src/test/java/com/ning/billing/util/UtilTestSuiteWithEmbeddedDB.java b/util/src/test/java/com/ning/billing/util/UtilTestSuiteWithEmbeddedDB.java
index 410b21a..39a9731 100644
--- a/util/src/test/java/com/ning/billing/util/UtilTestSuiteWithEmbeddedDB.java
+++ b/util/src/test/java/com/ning/billing/util/UtilTestSuiteWithEmbeddedDB.java
@@ -52,8 +52,6 @@ public abstract class UtilTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
@Inject
protected InternalCallContextFactory internalCallContextFactory;
@Inject
- protected CacheControllerDispatcher cacheControllerDispatcher;
- @Inject
protected DefaultCustomFieldUserApi customFieldUserApi;
@Inject
protected CustomFieldDao customFieldDao;
@@ -76,8 +74,9 @@ public abstract class UtilTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
@Override
@BeforeMethod(groups = "slow")
- public void beforeMethod() throws Exception {
+ public void beforeMethod() throws Exception {
super.beforeMethod();
+ controlCacheDispatcher.clearAll();
eventBus.start();
}