killbill-memoizeit
Changes
account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java 102(+70 -32)
account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java 2(+1 -1)
util/src/main/resources/ehcache.xml 26(+26 -0)
Details
diff --git a/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java b/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java
index 3b918f6..41791b6 100644
--- a/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java
+++ b/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java
@@ -22,52 +22,72 @@ import java.util.UUID;
import javax.inject.Inject;
import org.killbill.billing.ErrorCode;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountEmail;
import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.account.api.DefaultAccount;
import org.killbill.billing.account.api.DefaultAccountEmail;
import org.killbill.billing.account.api.DefaultImmutableAccountData;
+import org.killbill.billing.account.api.DefaultMutableAccountData;
import org.killbill.billing.account.api.ImmutableAccountData;
import org.killbill.billing.account.api.MutableAccountData;
+import org.killbill.billing.account.api.user.DefaultAccountApiBase;
import org.killbill.billing.account.dao.AccountDao;
import org.killbill.billing.account.dao.AccountEmailModelDao;
import org.killbill.billing.account.dao.AccountModelDao;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.cache.AccountBCDCacheLoader;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheController;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.cache.CacheLoaderArgument;
+import org.killbill.billing.util.cache.ImmutableAccountCacheLoader.LoaderCallback;
+import org.killbill.billing.util.dao.NonEntityDao;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
-public class DefaultAccountInternalApi implements AccountInternalApi {
+public class DefaultAccountInternalApi extends DefaultAccountApiBase implements AccountInternalApi {
private final AccountDao accountDao;
+ private final CacheControllerDispatcher cacheControllerDispatcher;
+ private final CacheController accountCacheController;
+ private final CacheController bcdCacheController;
+ private final NonEntityDao nonEntityDao;
@Inject
- public DefaultAccountInternalApi(final AccountDao accountDao) {
+ public DefaultAccountInternalApi(final AccountDao accountDao,
+ final NonEntityDao nonEntityDao,
+ final CacheControllerDispatcher cacheControllerDispatcher) {
+ super(accountDao, nonEntityDao, cacheControllerDispatcher);
this.accountDao = accountDao;
+ this.nonEntityDao = nonEntityDao;
+ this.cacheControllerDispatcher = cacheControllerDispatcher;
+ this.accountCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_IMMUTABLE);
+ this.bcdCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_BCD);
}
@Override
public Account getAccountById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
- final AccountModelDao account = accountDao.getById(accountId, context);
- if (account == null) {
- throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
- }
- return new DefaultAccount(account);
+ return super.getAccountById(accountId, context);
+ }
+
+ @Override
+ public Account getAccountByKey(final String key, final InternalTenantContext context) throws AccountApiException {
+ return super.getAccountByKey(key, context);
}
@Override
public Account getAccountByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
- final AccountModelDao accountModelDao = getAccountModelDaoByRecordId(recordId, context);
- return new DefaultAccount(accountModelDao);
+ return super.getAccountByRecordId(recordId, context);
}
@Override
public void updateBCD(final String externalKey, final int bcd,
- final InternalCallContext context) throws AccountApiException {
+ final InternalCallContext context) throws AccountApiException {
final Account currentAccount = getAccountByKey(externalKey, context);
if (currentAccount == null) {
throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, externalKey);
@@ -76,13 +96,15 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
final MutableAccountData mutableAccountData = currentAccount.toMutableAccountData();
mutableAccountData.setBillCycleDayLocal(bcd);
final AccountModelDao accountToUpdate = new AccountModelDao(currentAccount.getId(), mutableAccountData);
+ bcdCacheController.putIfAbsent(currentAccount.getId(), new Integer(bcd));
accountDao.update(accountToUpdate, context);
}
@Override
public int getBCD(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
- final Account account = getAccountById(accountId, context);
- return account.getBillCycleDayLocal();
+ final CacheLoaderArgument arg = createBCDCacheLoaderArgument(context);
+ final Integer result = (Integer) bcdCacheController.get(accountId, arg);
+ return result != null ? result : DefaultMutableAccountData.DEFAULT_BILLING_CYCLE_DAY_LOCAL;
}
@Override
@@ -98,15 +120,6 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
}
@Override
- public Account getAccountByKey(final String key, final InternalTenantContext context) throws AccountApiException {
- final AccountModelDao accountModelDao = accountDao.getAccountByKey(key, context);
- if (accountModelDao == null) {
- throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
- }
- return new DefaultAccount(accountModelDao);
- }
-
- @Override
public void removePaymentMethod(final UUID accountId, final InternalCallContext context) throws AccountApiException {
updatePaymentMethod(accountId, null, context);
}
@@ -125,20 +138,14 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
@Override
public ImmutableAccountData getImmutableAccountDataById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
- final Account account = getAccountById(accountId, context);
- return new DefaultImmutableAccountData(account);
- }
-
- @Override
- public ImmutableAccountData getImmutableAccountDataByKey(final String key, final InternalTenantContext context) throws AccountApiException {
- final Account account = getAccountByKey(key, context);
- return new DefaultImmutableAccountData(account);
+ final Long recordId = nonEntityDao.retrieveRecordIdFromObject(accountId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+ return getImmutableAccountDataByRecordId(recordId, context);
}
@Override
public ImmutableAccountData getImmutableAccountDataByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
- final Account account = getAccountByRecordId(recordId, context);
- return new DefaultImmutableAccountData(account);
+ final CacheLoaderArgument arg = createImmutableAccountCacheLoaderArgument(context);
+ return (ImmutableAccountData) accountCacheController.get(recordId, arg);
}
private AccountModelDao getAccountModelDaoByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
@@ -149,5 +156,36 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
return accountModelDao;
}
+ private int getBCDInternal(final UUID accountId, final InternalTenantContext context) {
+ final Long bcd = accountDao.getAccountBCD(accountId, context);
+ return bcd != null ? bcd.intValue() : DefaultMutableAccountData.DEFAULT_BILLING_CYCLE_DAY_LOCAL;
+ }
+
+ private CacheLoaderArgument createImmutableAccountCacheLoaderArgument(final InternalTenantContext context) {
+ final LoaderCallback loaderCallback = new LoaderCallback() {
+ @Override
+ public Object loadAccount(final Long recordId, final InternalTenantContext context) {
+ final Account account = getAccountByRecordIdInternal(recordId, context);
+ return account != null ? new DefaultImmutableAccountData(account) : null;
+ }
+ };
+ final Object[] args = new Object[1];
+ args[0] = loaderCallback;
+ final ObjectType irrelevant = null;
+ return new CacheLoaderArgument(irrelevant, args, context);
+ }
+ private CacheLoaderArgument createBCDCacheLoaderArgument(final InternalTenantContext context) {
+ final AccountBCDCacheLoader.LoaderCallback loaderCallback = new AccountBCDCacheLoader.LoaderCallback() {
+ @Override
+ public Object loadAccountBCD(final UUID accountId, final InternalTenantContext context) {
+ int bcd = getBCDInternal(accountId, context);
+ return new Integer(bcd);
+ }
+ };
+ final Object[] args = new Object[1];
+ args[0] = loaderCallback;
+ final ObjectType irrelevant = null;
+ return new CacheLoaderArgument(irrelevant, args, context);
+ }
}
diff --git a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountApiBase.java b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountApiBase.java
new file mode 100644
index 0000000..7792ab4
--- /dev/null
+++ b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountApiBase.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.account.api.user;
+
+import java.util.UUID;
+
+import org.killbill.billing.ErrorCode;
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.account.api.DefaultAccount;
+import org.killbill.billing.account.api.DefaultImmutableAccountData;
+import org.killbill.billing.account.dao.AccountDao;
+import org.killbill.billing.account.dao.AccountModelDao;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheController;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.dao.NonEntityDao;
+
+public class DefaultAccountApiBase {
+
+ private final AccountDao accountDao;
+ private final CacheControllerDispatcher cacheControllerDispatcher;
+ private final CacheController accountCacheController;
+ private final NonEntityDao nonEntityDao;
+
+ public DefaultAccountApiBase(final AccountDao accountDao,
+ final NonEntityDao nonEntityDao,
+ final CacheControllerDispatcher cacheControllerDispatcher) {
+ this.accountDao = accountDao;
+ this.nonEntityDao = nonEntityDao;
+ this.cacheControllerDispatcher = cacheControllerDispatcher;
+ this.accountCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_IMMUTABLE);
+ }
+
+ protected Account getAccountById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
+ final Long recordId = nonEntityDao.retrieveRecordIdFromObject(accountId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+ final Account account = getAccountByRecordIdInternal(recordId, context);
+ if (account == null) {
+ throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
+ }
+ accountCacheController.putIfAbsent(accountId, new DefaultImmutableAccountData(account));
+ return account;
+ }
+
+ protected Account getAccountByKey(final String key, final InternalTenantContext context) throws AccountApiException {
+ final AccountModelDao accountModelDao = accountDao.getAccountByKey(key, context);
+ if (accountModelDao == null) {
+ throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
+ }
+ final Account account = new DefaultAccount(accountModelDao);
+ accountCacheController.putIfAbsent(account.getId(), new DefaultImmutableAccountData(account));
+ return account;
+ }
+
+ protected Account getAccountByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
+ final Account account = getAccountByRecordIdInternal(recordId, context);
+ if (account == null) {
+ throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_RECORD_ID, recordId);
+ }
+ return account;
+ }
+
+ protected Account getAccountByRecordIdInternal(final Long recordId, final InternalTenantContext context) {
+ final AccountModelDao accountModelDao = accountDao.getByRecordId(recordId, context);
+ return accountModelDao != null ? new DefaultAccount(accountModelDao) : null;
+ }
+}
diff --git a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
index 55fb71b..b137cc0 100644
--- a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
@@ -32,9 +32,12 @@ import org.killbill.billing.account.api.DefaultAccountEmail;
import org.killbill.billing.account.dao.AccountDao;
import org.killbill.billing.account.dao.AccountEmailModelDao;
import org.killbill.billing.account.dao.AccountModelDao;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.SourcePaginationBuilder;
@@ -45,17 +48,35 @@ import com.google.inject.Inject;
import static org.killbill.billing.util.entity.dao.DefaultPaginationHelper.getEntityPaginationNoException;
-public class DefaultAccountUserApi implements AccountUserApi {
+public class DefaultAccountUserApi extends DefaultAccountApiBase implements AccountUserApi {
private final InternalCallContextFactory internalCallContextFactory;
private final AccountDao accountDao;
@Inject
- public DefaultAccountUserApi(final InternalCallContextFactory internalCallContextFactory, final AccountDao accountDao) {
+ public DefaultAccountUserApi(final AccountDao accountDao,
+ final NonEntityDao nonEntityDao,
+ final CacheControllerDispatcher cacheControllerDispatcher,
+ final InternalCallContextFactory internalCallContextFactory) {
+ super(accountDao, nonEntityDao, cacheControllerDispatcher);
this.internalCallContextFactory = internalCallContextFactory;
this.accountDao = accountDao;
}
+
+ @Override
+ public Account getAccountByKey(final String key, final TenantContext context) throws AccountApiException {
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
+ return getAccountByKey(key, internalTenantContext);
+ }
+
+ @Override
+ public Account getAccountById(final UUID id, final TenantContext context) throws AccountApiException {
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
+ return getAccountById(id, internalTenantContext);
+ }
+
+
@Override
public Account createAccount(final AccountData data, final CallContext context) throws AccountApiException {
// Not transactional, but there is a db constraint on that column
@@ -69,25 +90,6 @@ public class DefaultAccountUserApi implements AccountUserApi {
return new DefaultAccount(account);
}
- @Override
- public Account getAccountByKey(final String key, final TenantContext context) throws AccountApiException {
- final AccountModelDao account = accountDao.getAccountByKey(key, internalCallContextFactory.createInternalTenantContext(context));
- if (account == null) {
- throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
- }
-
- return new DefaultAccount(account);
- }
-
- @Override
- public Account getAccountById(final UUID id, final TenantContext context) throws AccountApiException {
- final AccountModelDao account = accountDao.getById(id, internalCallContextFactory.createInternalTenantContext(context));
- if (account == null) {
- throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, id);
- }
-
- return new DefaultAccount(account);
- }
@Override
public Pagination<Account> searchAccounts(final String searchKey, final Long offset, final Long limit, final TenantContext context) {
diff --git a/account/src/main/java/org/killbill/billing/account/dao/AccountDao.java b/account/src/main/java/org/killbill/billing/account/dao/AccountDao.java
index 2b79ca2..ec9b237 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/AccountDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/AccountDao.java
@@ -28,26 +28,28 @@ import org.killbill.billing.util.entity.dao.EntityDao;
public interface AccountDao extends EntityDao<AccountModelDao, Account, AccountApiException> {
- public AccountModelDao getAccountByKey(String key, InternalTenantContext context);
+ AccountModelDao getAccountByKey(String key, InternalTenantContext context);
- public Pagination<AccountModelDao> searchAccounts(String searchKey, Long offset, Long limit, InternalTenantContext context);
+ Pagination<AccountModelDao> searchAccounts(String searchKey, Long offset, Long limit, InternalTenantContext context);
/**
* @throws AccountApiException when externalKey is null
*/
- public UUID getIdFromKey(String externalKey, InternalTenantContext context) throws AccountApiException;
+ UUID getIdFromKey(String externalKey, InternalTenantContext context) throws AccountApiException;
/**
* @param accountId the id of the account
* @param paymentMethodId the is of the current default paymentMethod
*/
- public void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
+ void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
- public void update(AccountModelDao account, InternalCallContext context) throws AccountApiException;
+ void update(AccountModelDao account, InternalCallContext context) throws AccountApiException;
- public void addEmail(AccountEmailModelDao email, InternalCallContext context) throws AccountApiException;
+ void addEmail(AccountEmailModelDao email, InternalCallContext context) throws AccountApiException;
- public void removeEmail(AccountEmailModelDao email, InternalCallContext context);
+ void removeEmail(AccountEmailModelDao email, InternalCallContext context);
- public List<AccountEmailModelDao> getEmailsByAccountId(UUID accountId, InternalTenantContext context);
+ List<AccountEmailModelDao> getEmailsByAccountId(UUID accountId, InternalTenantContext context);
+
+ Long getAccountBCD(UUID accountId, InternalTenantContext context);
}
diff --git a/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java b/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
index 8eeff93..b566df9 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
@@ -18,11 +18,6 @@ package org.killbill.billing.account.dao;
import java.util.UUID;
-import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
-import org.skife.jdbi.v2.sqlobject.SqlQuery;
-import org.skife.jdbi.v2.sqlobject.SqlUpdate;
-
import org.killbill.billing.account.api.Account;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
@@ -30,6 +25,10 @@ import org.killbill.billing.util.audit.ChangeType;
import org.killbill.billing.util.entity.dao.Audited;
import org.killbill.billing.util.entity.dao.EntitySqlDao;
import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
@EntitySqlDaoStringTemplate
public interface AccountSqlDao extends EntitySqlDao<AccountModelDao, Account> {
@@ -42,6 +41,10 @@ public interface AccountSqlDao extends EntitySqlDao<AccountModelDao, Account> {
public UUID getIdFromKey(@Bind("externalKey") final String key,
@BindBean final InternalTenantContext context);
+ @SqlQuery
+ public Long getBCD(@Bind("id") String accountId,
+ @BindBean final InternalTenantContext context);
+
@SqlUpdate
@Audited(ChangeType.UPDATE)
public void update(@BindBean final AccountModelDao account,
diff --git a/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
index b14c677..79f7b92 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
@@ -246,4 +246,13 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
});
}
+ @Override
+ public Long getAccountBCD(final UUID accountId, final InternalTenantContext context) {
+ return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Long>() {
+ @Override
+ public Long inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+ return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getBCD(accountId.toString(), context);
+ }
+ });
+ }
}
diff --git a/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg b/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
index 0f5bb37..a500028 100644
--- a/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
+++ b/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
@@ -86,6 +86,12 @@ getAccountByKey() ::= <<
where external_key = :externalKey <AND_CHECK_TENANT()>;
>>
+getBCD() ::= <<
+ select billing_cycle_day_local
+ from accounts
+ where id = :id <AND_CHECK_TENANT()>;
+>>
+
searchQuery(prefix) ::= <<
<idField(prefix)> = :searchKey
or <prefix>name like :likeSearchKey
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
index 1843b08..f3d7863 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
@@ -53,7 +53,7 @@ public class TestDefaultAccountUserApiWithMocks extends AccountTestSuiteNoDB {
@BeforeMethod(groups = "fast")
public void setUp() throws Exception {
accountDao = new MockAccountDao(Mockito.mock(PersistentBus.class));
- accountUserApi = new DefaultAccountUserApi(internalFactory, accountDao);
+ accountUserApi = new DefaultAccountUserApi(accountDao, nonEntityDao, controllerDispatcher, internalFactory);
}
@Test(groups = "fast", description = "Test Account create API")
diff --git a/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java b/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
index 04a8bbe..d60ef82 100644
--- a/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
+++ b/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
@@ -163,4 +163,10 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account,
}));
}
+ @Override
+ public Long getAccountBCD(final UUID accountId, final InternalTenantContext context) {
+ final AccountModelDao account = getById(accountId, context);
+ return account != null ? account.getBillingCycleDayLocal() : 0L;
+ }
+
}
diff --git a/api/src/main/java/org/killbill/billing/account/api/AccountInternalApi.java b/api/src/main/java/org/killbill/billing/account/api/AccountInternalApi.java
index 9a61b19..4f7a92f 100644
--- a/api/src/main/java/org/killbill/billing/account/api/AccountInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/account/api/AccountInternalApi.java
@@ -44,8 +44,6 @@ public interface AccountInternalApi {
ImmutableAccountData getImmutableAccountDataById(UUID accountId, InternalTenantContext context) throws AccountApiException;
- ImmutableAccountData getImmutableAccountDataByKey(String key, InternalTenantContext context) throws AccountApiException;
-
ImmutableAccountData getImmutableAccountDataByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index a081939..c962709 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -243,8 +243,6 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
@Inject
protected IDBI idbi;
- @Inject
- protected CacheControllerDispatcher controlCacheDispatcher;
@Inject
protected TestApiListener busHandler;
@@ -273,9 +271,6 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
//Thread.currentThread().setContextClassLoader(null);
log.debug("RESET TEST FRAMEWORK");
-
- controlCacheDispatcher.clearAll();
-
overdueConfigCache.loadDefaultOverdueConfig((OverdueConfig) null);
clock.resetDeltaFromReality();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
index 012fa68..6bde96a 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
@@ -85,8 +85,6 @@ public class TestPublicBus extends TestIntegrationBase {
log.debug("RESET TEST FRAMEWORK");
- controlCacheDispatcher.clearAll();
-
overdueConfigCache.loadDefaultOverdueConfig((OverdueConfig) null);
clock.resetDeltaFromReality();
diff --git a/usage/src/test/java/org/killbill/billing/usage/glue/TestUsageModuleWithEmbeddedDB.java b/usage/src/test/java/org/killbill/billing/usage/glue/TestUsageModuleWithEmbeddedDB.java
index 4db4fd8..1e71a18 100644
--- a/usage/src/test/java/org/killbill/billing/usage/glue/TestUsageModuleWithEmbeddedDB.java
+++ b/usage/src/test/java/org/killbill/billing/usage/glue/TestUsageModuleWithEmbeddedDB.java
@@ -20,6 +20,8 @@ package org.killbill.billing.usage.glue;
import org.killbill.billing.GuicyKillbillTestWithEmbeddedDBModule;
import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.util.glue.CacheModule;
+import org.killbill.billing.util.glue.NonEntityDaoModule;
public class TestUsageModuleWithEmbeddedDB extends TestUsageModule {
@@ -32,5 +34,7 @@ public class TestUsageModuleWithEmbeddedDB extends TestUsageModule {
super.configure();
install(new GuicyKillbillTestWithEmbeddedDBModule(configSource));
+ install(new CacheModule(configSource));
+ install(new NonEntityDaoModule(configSource));
}
}
diff --git a/util/src/main/java/org/killbill/billing/util/cache/AccountBCDCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/AccountBCDCacheLoader.java
new file mode 100644
index 0000000..d88ea69
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/cache/AccountBCDCacheLoader.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.util.cache;
+
+import java.util.UUID;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+
+public class AccountBCDCacheLoader extends BaseCacheLoader {
+
+ @Override
+ public CacheType getCacheType() {
+ return CacheType.ACCOUNT_BCD;
+ }
+
+ @Override
+ public Object load(final Object key, final Object argument) {
+
+ checkCacheLoaderStatus();
+
+ if (!(key instanceof UUID)) {
+ throw new IllegalArgumentException("Unexpected key type of " + key.getClass().getName());
+ }
+
+ if (!(argument instanceof CacheLoaderArgument)) {
+ throw new IllegalArgumentException("Unexpected argument type of " + argument.getClass().getName());
+ }
+
+ final CacheLoaderArgument cacheLoaderArgument = (CacheLoaderArgument) argument;
+
+ if (cacheLoaderArgument.getArgs() == null ||
+ !(cacheLoaderArgument.getArgs()[0] instanceof LoaderCallback)) {
+ throw new IllegalArgumentException("Missing LoaderCallback from the arguments ");
+ }
+
+ final LoaderCallback callback = (LoaderCallback) cacheLoaderArgument.getArgs()[0];
+ return callback.loadAccountBCD((UUID) key, cacheLoaderArgument.getInternalTenantContext());
+ }
+
+ public interface LoaderCallback {
+ Object loadAccountBCD(final UUID accountId, final InternalTenantContext context);
+ }
+}
diff --git a/util/src/main/java/org/killbill/billing/util/cache/Cachable.java b/util/src/main/java/org/killbill/billing/util/cache/Cachable.java
index 767cc94..bfc0b27 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/Cachable.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/Cachable.java
@@ -25,20 +25,22 @@ import java.lang.annotation.Target;
@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 final String OBJECT_ID_CACHE_NAME = "object-id";
- public final String AUDIT_LOG_CACHE_NAME = "audit-log";
- public final String AUDIT_LOG_VIA_HISTORY_CACHE_NAME = "audit-log-via-history";
- public final String TENANT_CATALOG_CACHE_NAME = "tenant-catalog";
- public final String TENANT_OVERDUE_CONFIG_CACHE_NAME = "tenant-overdue-config";
- public final String TENANT_KV_CACHE_NAME = "tenant-kv";
- public final String OVERRIDDEN_PLAN_CACHE_NAME = "overridden-plan";
-
- public CacheType value();
-
- public enum CacheType {
+ String RECORD_ID_CACHE_NAME = "record-id";
+ String ACCOUNT_RECORD_ID_CACHE_NAME = "account-record-id";
+ String TENANT_RECORD_ID_CACHE_NAME = "tenant-record-id";
+ String OBJECT_ID_CACHE_NAME = "object-id";
+ String AUDIT_LOG_CACHE_NAME = "audit-log";
+ String AUDIT_LOG_VIA_HISTORY_CACHE_NAME = "audit-log-via-history";
+ String TENANT_CATALOG_CACHE_NAME = "tenant-catalog";
+ String TENANT_OVERDUE_CONFIG_CACHE_NAME = "tenant-overdue-config";
+ String TENANT_KV_CACHE_NAME = "tenant-kv";
+ String OVERRIDDEN_PLAN_CACHE_NAME = "overridden-plan";
+ String ACCOUNT_IMMUTABLE_CACHE_NAME = "account-immutable";
+ String ACCOUNT_BCD_CACHE_NAME = "account-bcd";
+
+ CacheType value();
+
+ enum CacheType {
/* Mapping from object 'id (UUID)' -> object 'recordId (Long' */
RECORD_ID(RECORD_ID_CACHE_NAME, false),
@@ -68,7 +70,13 @@ public @interface Cachable {
TENANT_KV(TENANT_KV_CACHE_NAME, false),
/* Overwritten plans */
- OVERRIDDEN_PLAN(OVERRIDDEN_PLAN_CACHE_NAME, false);
+ OVERRIDDEN_PLAN(OVERRIDDEN_PLAN_CACHE_NAME, false),
+
+ /* Immutable account data config cache */
+ ACCOUNT_IMMUTABLE(ACCOUNT_IMMUTABLE_CACHE_NAME, false),
+
+ /* Account BCD config cache */
+ ACCOUNT_BCD(ACCOUNT_BCD_CACHE_NAME, false);
private final String cacheName;
private final boolean isKeyPrefixedWithTableName;
diff --git a/util/src/main/java/org/killbill/billing/util/cache/CacheController.java b/util/src/main/java/org/killbill/billing/util/cache/CacheController.java
index 5743f65..2c6be1e 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/CacheController.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/CacheController.java
@@ -20,13 +20,17 @@ import org.killbill.billing.util.cache.Cachable.CacheType;
public interface CacheController<K, V> {
- public void add(K key, V value);
+ void add(K key, V value);
- public V get(K key, CacheLoaderArgument objectType);
+ V get(K key, CacheLoaderArgument objectType);
- public boolean remove(K key);
+ V get(K key);
- public int size();
+ boolean remove(K key);
+
+ void putIfAbsent(final K key, V value);
+
+ int size();
void removeAll();
diff --git a/util/src/main/java/org/killbill/billing/util/cache/EhCacheBasedCacheController.java b/util/src/main/java/org/killbill/billing/util/cache/EhCacheBasedCacheController.java
index 1f7998f..08d04d2 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/EhCacheBasedCacheController.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/EhCacheBasedCacheController.java
@@ -18,6 +18,8 @@
package org.killbill.billing.util.cache;
+import javax.annotation.Nullable;
+
import org.killbill.billing.util.cache.Cachable.CacheType;
import net.sf.ehcache.Ehcache;
@@ -39,12 +41,18 @@ public class EhCacheBasedCacheController<K, V> implements CacheController<K, V>
}
@Override
- public V get(final K key, final CacheLoaderArgument cacheLoaderArgument) {
- final Element element = cache.getWithLoader(key, null, cacheLoaderArgument);
- if (element == null || element.getObjectValue() == null || element.getObjectValue().equals(BaseCacheLoader.EMPTY_VALUE_PLACEHOLDER)) {
- return null;
- }
- return (V) element.getObjectValue();
+ public V get(final K key, @Nullable final CacheLoaderArgument cacheLoaderArgument) {
+ return getWithOrWithoutCacheLoaderArgument(key, cacheLoaderArgument);
+ }
+
+ @Override
+ public V get(final K key) {
+ return getWithOrWithoutCacheLoaderArgument(key, null);
+ }
+
+ public void putIfAbsent(final K key, V value) {
+ final Element element = new Element(key, value);
+ cache.putIfAbsent(element);
}
@Override
@@ -66,4 +74,13 @@ public class EhCacheBasedCacheController<K, V> implements CacheController<K, V>
public CacheType getCacheType() {
return cacheType;
}
+
+ private V getWithOrWithoutCacheLoaderArgument(final K key, @Nullable final CacheLoaderArgument cacheLoaderArgument) {
+ final Element element = cacheLoaderArgument != null ? cache.getWithLoader(key, null, cacheLoaderArgument) : cache.get(key);
+ if (element == null || element.getObjectValue() == null || element.getObjectValue().equals(BaseCacheLoader.EMPTY_VALUE_PLACEHOLDER)) {
+ return null;
+ }
+ return (V) element.getObjectValue();
+ }
+
}
diff --git a/util/src/main/java/org/killbill/billing/util/cache/EhCacheCacheManagerProvider.java b/util/src/main/java/org/killbill/billing/util/cache/EhCacheCacheManagerProvider.java
index 42d8966..269ff66 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/EhCacheCacheManagerProvider.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/EhCacheCacheManagerProvider.java
@@ -51,6 +51,8 @@ public class EhCacheCacheManagerProvider implements Provider<CacheManager> {
@Inject
public EhCacheCacheManagerProvider(final MetricRegistry metricRegistry,
final CacheConfig cacheConfig,
+ final ImmutableAccountCacheLoader accountCacheLoader,
+ final AccountBCDCacheLoader accountBCDCacheLoader,
final RecordIdCacheLoader recordIdCacheLoader,
final AccountRecordIdCacheLoader accountRecordIdCacheLoader,
final TenantRecordIdCacheLoader tenantRecordIdCacheLoader,
@@ -63,6 +65,8 @@ public class EhCacheCacheManagerProvider implements Provider<CacheManager> {
final OverriddenPlanCacheLoader overriddenPlanCacheLoader) {
this.metricRegistry = metricRegistry;
this.cacheConfig = cacheConfig;
+ cacheLoaders.add(accountCacheLoader);
+ cacheLoaders.add(accountBCDCacheLoader);
cacheLoaders.add(recordIdCacheLoader);
cacheLoaders.add(accountRecordIdCacheLoader);
cacheLoaders.add(tenantRecordIdCacheLoader);
diff --git a/util/src/main/java/org/killbill/billing/util/cache/ImmutableAccountCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/ImmutableAccountCacheLoader.java
new file mode 100644
index 0000000..866c44e
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/cache/ImmutableAccountCacheLoader.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.util.cache;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+
+public class ImmutableAccountCacheLoader extends BaseCacheLoader {
+
+ @Override
+ public CacheType getCacheType() {
+ return CacheType.ACCOUNT_IMMUTABLE;
+ }
+
+ @Override
+ public Object load(final Object key, final Object argument) {
+
+ checkCacheLoaderStatus();
+
+ if (!(key instanceof Long)) {
+ throw new IllegalArgumentException("Unexpected key type of " + key.getClass().getName());
+ }
+
+ if (!(argument instanceof CacheLoaderArgument)) {
+ throw new IllegalArgumentException("Unexpected argument type of " + argument.getClass().getName());
+ }
+
+ final CacheLoaderArgument cacheLoaderArgument = (CacheLoaderArgument) argument;
+
+ if (cacheLoaderArgument.getArgs() == null ||
+ !(cacheLoaderArgument.getArgs()[0] instanceof LoaderCallback)) {
+ throw new IllegalArgumentException("Missing LoaderCallback from the arguments ");
+ }
+
+ final LoaderCallback callback = (LoaderCallback) cacheLoaderArgument.getArgs()[0];
+ return callback.loadAccount((Long) key, cacheLoaderArgument.getInternalTenantContext());
+ }
+
+ public interface LoaderCallback {
+ Object loadAccount(final Long recordId, final InternalTenantContext context);
+ }
+}
diff --git a/util/src/main/java/org/killbill/billing/util/cache/TenantCatalogCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/TenantCatalogCacheLoader.java
index 6a1accf..897e75d 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/TenantCatalogCacheLoader.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/TenantCatalogCacheLoader.java
@@ -81,7 +81,6 @@ public class TenantCatalogCacheLoader extends BaseCacheLoader {
}
public interface LoaderCallback {
-
public Object loadCatalog(final List<String> catalogXMLs, final Long tenantRecordId) throws CatalogApiException;
}
}
util/src/main/resources/ehcache.xml 26(+26 -0)
diff --git a/util/src/main/resources/ehcache.xml b/util/src/main/resources/ehcache.xml
index 7769245..d172871 100644
--- a/util/src/main/resources/ehcache.xml
+++ b/util/src/main/resources/ehcache.xml
@@ -168,6 +168,32 @@
properties=""/>
</cache>
+ <cache name="account-immutable"
+ maxElementsInMemory="1000"
+ maxElementsOnDisk="0"
+ overflowToDisk="false"
+ diskPersistent="false"
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
+ <cacheEventListenerFactory
+ class="org.killbill.billing.util.cache.ExpirationListenerFactory"
+ properties=""/>
+ </cache>
+
+ <cache name="account-bcd"
+ maxElementsInMemory="1000"
+ maxElementsOnDisk="0"
+ overflowToDisk="false"
+ diskPersistent="false"
+ memoryStoreEvictionPolicy="LFU"
+ statistics="true"
+ >
+ <cacheEventListenerFactory
+ class="org.killbill.billing.util.cache.ExpirationListenerFactory"
+ properties=""/>
+ </cache>
+
</ehcache>
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java
index eac77a7..565027e 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java
@@ -19,6 +19,7 @@ package org.killbill.billing;
import javax.inject.Inject;
import javax.sql.DataSource;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.commons.embeddeddb.EmbeddedDB;
import org.skife.jdbi.v2.IDBI;
import org.slf4j.Logger;
@@ -40,6 +41,10 @@ public class GuicyKillbillTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
@Inject
protected IDBI dbi;
+ @Inject
+ protected CacheControllerDispatcher controlCacheDispatcher;
+
+
@BeforeSuite(groups = "slow")
public void beforeSuite() throws Exception {
DBTestingHelper.get().start();
@@ -51,6 +56,7 @@ public class GuicyKillbillTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
DBTestingHelper.get().getInstance().cleanupAllTables();
} catch (final Exception ignored) {
}
+ controlCacheDispatcher.clearAll();
}
@AfterSuite(groups = "slow")
diff --git a/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java b/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
index caff3f8..df64546 100644
--- a/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
+++ b/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
@@ -59,8 +59,6 @@ public abstract class UtilTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
@Inject
protected PersistentBus eventBus;
@Inject
- protected CacheControllerDispatcher controlCacheDispatcher;
- @Inject
protected NonEntityDao nonEntityDao;
@Inject
protected InternalCallContextFactory internalCallContextFactory;
@@ -112,8 +110,6 @@ public abstract class UtilTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
eventBus.start();
eventBus.register(eventsListener);
- controlCacheDispatcher.clearAll();
-
// Make sure we start with a clean state
assertListenerStatus();
}