killbill-uncached

Merge branch 'caching'

10/5/2015 4:23:43 PM

Changes

pom.xml 2(+1 -1)

Details

diff --git a/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java b/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
index 25384b3..957b2e2 100644
--- a/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
@@ -295,15 +295,18 @@ public class DefaultAccount extends EntityBase implements Account {
             accountData.setCurrency(currentAccount.getCurrency());
         }
 
-        if (billCycleDayLocal != null && billCycleDayLocal != DEFAULT_BILLING_CYCLE_DAY_LOCAL && currentAccount.getBillCycleDayLocal() != null && currentAccount.getBillCycleDayLocal() != DEFAULT_BILLING_CYCLE_DAY_LOCAL && !billCycleDayLocal.equals(currentAccount.getBillCycleDayLocal())) {
-            throw new IllegalArgumentException(String.format("Killbill doesn't support updating the account BCD yet: new=%s, current=%s",
-                                                             billCycleDayLocal, currentAccount.getBillCycleDayLocal()));
-        } else if (billCycleDayLocal != null && billCycleDayLocal != DEFAULT_BILLING_CYCLE_DAY_LOCAL) {
-            // Junction sets it
+
+        if (currentAccount.getBillCycleDayLocal() != DEFAULT_BILLING_CYCLE_DAY_LOCAL && // There is already a BCD set
+            billCycleDayLocal != null && // and the proposed date is not null
+            billCycleDayLocal != DEFAULT_BILLING_CYCLE_DAY_LOCAL && // and the proposed date is not 0
+            !currentAccount.getBillCycleDayLocal().equals(billCycleDayLocal)) { // and it does not match we we have
+            throw new IllegalArgumentException(String.format("Killbill doesn't support updating the account BCD yet: new=%s, current=%s", billCycleDayLocal, currentAccount.getBillCycleDayLocal()));
+        } else if (currentAccount.getBillCycleDayLocal() == DEFAULT_BILLING_CYCLE_DAY_LOCAL && // There is *not* already a BCD set
+                   billCycleDayLocal != null && // and the value proposed is not null
+                   billCycleDayLocal != DEFAULT_BILLING_CYCLE_DAY_LOCAL) {  // and the proposed date is not 0
             accountData.setBillCycleDayLocal(billCycleDayLocal);
         } else {
-            // Default to current value
-            accountData.setBillCycleDayLocal(currentAccount.getBillCycleDayLocal() == null ? DEFAULT_BILLING_CYCLE_DAY_LOCAL : currentAccount.getBillCycleDayLocal());
+            accountData.setBillCycleDayLocal(currentAccount.getBillCycleDayLocal());
         }
 
         // Set all updatable fields with the new values if non null, otherwise defaults to the current values
@@ -336,6 +339,10 @@ public class DefaultAccount extends EntityBase implements Account {
         return new DefaultAccount(currentAccount.getId(), accountData);
     }
 
+    public ImmutableAccountData toImmutableAccountData() {
+        return new DefaultImmutableAccountData(this);
+    }
+
     @Override
     public String toString() {
         return "DefaultAccount [externalKey=" + externalKey +
diff --git a/account/src/main/java/org/killbill/billing/account/api/DefaultImmutableAccountData.java b/account/src/main/java/org/killbill/billing/account/api/DefaultImmutableAccountData.java
new file mode 100644
index 0000000..e1df215
--- /dev/null
+++ b/account/src/main/java/org/killbill/billing/account/api/DefaultImmutableAccountData.java
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+import java.util.UUID;
+
+import org.joda.time.DateTimeZone;
+import org.killbill.billing.catalog.api.Currency;
+
+public class DefaultImmutableAccountData implements ImmutableAccountData {
+
+    private final UUID id;
+    private final String externalKey;
+    private final Currency currency;
+    private final DateTimeZone dateTimeZone;
+
+    public DefaultImmutableAccountData(final UUID id, final String externalKey, final Currency currency, final DateTimeZone dateTimeZone) {
+        this.id = id;
+        this.externalKey = externalKey;
+        this.currency = currency;
+        this.dateTimeZone = dateTimeZone;
+    }
+
+    public DefaultImmutableAccountData(final Account account) {
+        this(account.getId(), account.getExternalKey(), account.getCurrency(), account.getTimeZone());
+    }
+
+    @Override
+    public UUID getId() {
+        return id;
+    }
+
+    @Override
+    public String getExternalKey() {
+        return externalKey;
+    }
+
+    @Override
+    public Currency getCurrency() {
+        return currency;
+    }
+
+    @Override
+    public DateTimeZone getTimeZone() {
+        return dateTimeZone;
+    }
+}
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 5502b4e..0903c13 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,66 +22,96 @@ 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.AccountData;
 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.entity.DefaultPagination;
-import org.killbill.billing.util.entity.Pagination;
+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;
-import com.google.common.collect.Iterators;
 
-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 updateAccount(final String externalKey, final AccountData accountData,
-                              final InternalCallContext context) throws AccountApiException {
+    public void updateBCD(final String externalKey, final int bcd,
+                          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);
         }
+        if (currentAccount.getBillCycleDayLocal() != DefaultMutableAccountData.DEFAULT_BILLING_CYCLE_DAY_LOCAL) {
+            throw new AccountApiException(ErrorCode.ACCOUNT_UPDATE_FAILED);
+        }
 
-        // Set unspecified (null) fields to their current values
-        final Account updatedAccount = new DefaultAccount(currentAccount.getId(), accountData);
-        final AccountModelDao accountToUpdate = new AccountModelDao(currentAccount.getId(), updatedAccount.mergeWithDelegate(currentAccount));
-
+        final MutableAccountData mutableAccountData = currentAccount.toMutableAccountData();
+        mutableAccountData.setBillCycleDayLocal(bcd);
+        final AccountModelDao accountToUpdate = new AccountModelDao(currentAccount.getId(), mutableAccountData);
+        bcdCacheController.remove(currentAccount.getId());
+        bcdCacheController.putIfAbsent(currentAccount.getId(), new Integer(bcd));
         accountDao.update(accountToUpdate, context);
     }
 
     @Override
+    public int getBCD(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
+        final CacheLoaderArgument arg = createBCDCacheLoaderArgument(context);
+        final Integer result = (Integer) bcdCacheController.get(accountId, arg);
+        return result != null ? result : DefaultMutableAccountData.DEFAULT_BILLING_CYCLE_DAY_LOCAL;
+    }
+
+    @Override
     public List<AccountEmail> getEmails(final UUID accountId,
                                         final InternalTenantContext context) {
         return ImmutableList.<AccountEmail>copyOf(Collections2.transform(accountDao.getEmailsByAccountId(accountId, context),
@@ -94,15 +124,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);
     }
@@ -119,6 +140,18 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
         return accountModelDao.getId();
     }
 
+    @Override
+    public ImmutableAccountData getImmutableAccountDataById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
+        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 CacheLoaderArgument arg = createImmutableAccountCacheLoaderArgument(context);
+        return (ImmutableAccountData) accountCacheController.get(recordId, arg);
+    }
+
     private AccountModelDao getAccountModelDaoByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
         final AccountModelDao accountModelDao = accountDao.getByRecordId(recordId, context);
         if (accountModelDao == null) {
@@ -126,4 +159,37 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
         }
         return accountModelDao;
     }
+
+    private int getBCDInternal(final UUID accountId, final InternalTenantContext context) {
+        final Integer bcd = accountDao.getAccountBCD(accountId, context);
+        return bcd != null ? bcd : 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..c5cae6d 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);
+
+    Integer 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..5395c85 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 Integer 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..31c33e3 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 Integer getAccountBCD(final UUID accountId, final InternalTenantContext context) {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Integer>() {
+            @Override
+            public Integer 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..e9715dd 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 Integer getAccountBCD(final UUID accountId, final InternalTenantContext context) {
+        final AccountModelDao account = getById(accountId, context);
+        return account != null ? account.getBillingCycleDayLocal() : 0;
+    }
+
 }
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 8e6ab3c..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
@@ -21,23 +21,29 @@ import java.util.UUID;
 
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.util.entity.Pagination;
 
 public interface AccountInternalApi {
 
-    public Account getAccountByKey(String key, InternalTenantContext context) throws AccountApiException;
+    Account getAccountByKey(String key, InternalTenantContext context) throws AccountApiException;
 
-    public Account getAccountById(UUID accountId, InternalTenantContext context) throws AccountApiException;
+    Account getAccountById(UUID accountId, InternalTenantContext context) throws AccountApiException;
 
-    public Account getAccountByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
+    Account getAccountByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
 
-    public void updateAccount(String key, AccountData accountData, InternalCallContext context) throws AccountApiException;
+    void updateBCD(String key, int bcd, InternalCallContext context) throws AccountApiException;
 
-    public List<AccountEmail> getEmails(UUID accountId, InternalTenantContext context);
+    int getBCD(UUID accountId, InternalTenantContext context) throws AccountApiException;
 
-    public void removePaymentMethod(UUID accountId, InternalCallContext context) throws AccountApiException;
+    List<AccountEmail> getEmails(UUID accountId, InternalTenantContext context);
 
-    public void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
+    void removePaymentMethod(UUID accountId, InternalCallContext context) throws AccountApiException;
+
+    void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
+
+    UUID getByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
+
+    ImmutableAccountData getImmutableAccountDataById(UUID accountId, InternalTenantContext context) throws AccountApiException;
+
+    ImmutableAccountData getImmutableAccountDataByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
 
-    public UUID getByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
 }
diff --git a/api/src/main/java/org/killbill/billing/entitlement/AccountEntitlements.java b/api/src/main/java/org/killbill/billing/entitlement/AccountEntitlements.java
index df3fd30..1136058 100644
--- a/api/src/main/java/org/killbill/billing/entitlement/AccountEntitlements.java
+++ b/api/src/main/java/org/killbill/billing/entitlement/AccountEntitlements.java
@@ -20,14 +20,14 @@ import java.util.Collection;
 import java.util.Map;
 import java.util.UUID;
 
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.entitlement.api.Entitlement;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
 
 // Wrapper object to save on DAO calls
 public interface AccountEntitlements {
 
-    public Account getAccount();
+    public ImmutableAccountData getAccount();
 
     // Map bundle id -> bundle
     public Map<UUID, SubscriptionBaseBundle> getBundles();
diff --git a/api/src/main/java/org/killbill/billing/entitlement/AccountEventsStreams.java b/api/src/main/java/org/killbill/billing/entitlement/AccountEventsStreams.java
index f7b558a..bd674fb 100644
--- a/api/src/main/java/org/killbill/billing/entitlement/AccountEventsStreams.java
+++ b/api/src/main/java/org/killbill/billing/entitlement/AccountEventsStreams.java
@@ -20,13 +20,13 @@ import java.util.Collection;
 import java.util.Map;
 import java.util.UUID;
 
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
 
 // Wrapper object to save on DAO calls
 public interface AccountEventsStreams {
 
-    public Account getAccount();
+    public ImmutableAccountData getAccount();
 
     // Map bundle id -> bundle
     public Map<UUID, SubscriptionBaseBundle> getBundles();
diff --git a/api/src/main/java/org/killbill/billing/junction/BillingEvent.java b/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
index 02c15d0..a08e8c3 100644
--- a/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
+++ b/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
@@ -34,10 +34,6 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
 
 public interface BillingEvent extends Comparable<BillingEvent> {
 
-    /**
-     * @return the account that this billing event is associated with
-     */
-    Account getAccount();
 
     /**
      * @return the billCycleDay in the account timezone as seen for that subscription at that time
diff --git a/api/src/main/java/org/killbill/billing/overdue/OverdueInternalApi.java b/api/src/main/java/org/killbill/billing/overdue/OverdueInternalApi.java
index afc01ca..0b376b8 100644
--- a/api/src/main/java/org/killbill/billing/overdue/OverdueInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/overdue/OverdueInternalApi.java
@@ -16,7 +16,7 @@
 
 package org.killbill.billing.overdue;
 
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.overdue.api.OverdueApiException;
 import org.killbill.billing.overdue.api.OverdueState;
 import org.killbill.billing.overdue.config.api.BillingState;
@@ -26,12 +26,12 @@ import org.killbill.billing.util.callcontext.TenantContext;
 
 public interface OverdueInternalApi {
 
-    public OverdueState refreshOverdueStateFor(Account overdueable, CallContext context) throws OverdueException, OverdueApiException;
+    public OverdueState refreshOverdueStateFor(ImmutableAccountData overdueable, CallContext context) throws OverdueException, OverdueApiException;
 
-    public void setOverrideBillingStateForAccount(Account overdueable, BillingState state, CallContext context) throws OverdueException;
+    public void setOverrideBillingStateForAccount(ImmutableAccountData overdueable, BillingState state, CallContext context) throws OverdueException;
 
-    public OverdueState getOverdueStateFor(Account overdueable, TenantContext context) throws OverdueException;
+    public OverdueState getOverdueStateFor(ImmutableAccountData overdueable, TenantContext context) throws OverdueException;
 
-    public BillingState getBillingStateFor(Account overdueable, TenantContext context) throws OverdueException;
+    public BillingState getBillingStateFor(ImmutableAccountData overdueable, TenantContext context) throws OverdueException;
 
 }
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
index 442f5f4..98c0ce5 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
@@ -40,6 +40,7 @@ import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.entitlement.api.SubscriptionBundle;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
+import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItemType;
@@ -75,7 +76,7 @@ public class TestIntegration extends TestIntegrationBase {
         // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE NextEvent.INVOICE
         //
 
-        TestDryRunArguments dryRun = new TestDryRunArguments("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
+        TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
                                                              SubscriptionEventType.START_BILLING, null, null, clock.getUTCNow(), null);
         Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
@@ -90,7 +91,7 @@ public class TestIntegration extends TestIntegrationBase {
         //
         // ADD ADD_ON ON THE SAME DAY
         //
-        dryRun = new TestDryRunArguments("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, null, null,
+        dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, null, null,
                                          SubscriptionEventType.START_BILLING, null, bpSubscription.getBundleId(), clock.getUTCNow(), null);
         dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("399.95")));
@@ -106,7 +107,7 @@ public class TestIntegration extends TestIntegrationBase {
         // CANCEL BP ON THE SAME DAY (we should have two cancellations, BP and AO)
         // There is no invoice created as we only adjust the previous invoice.
         //
-        dryRun = new TestDryRunArguments(null, null, null, null, null, SubscriptionEventType.STOP_BILLING, bpSubscription.getId(),
+        dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, null, null, null, null, null, SubscriptionEventType.STOP_BILLING, bpSubscription.getId(),
                                          bpSubscription.getBundleId(), clock.getUTCNow(), null);
         dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-399.95")));
@@ -153,7 +154,7 @@ public class TestIntegration extends TestIntegrationBase {
         //
         // CHANGE PLAN IMMEDIATELY AND EXPECT BOTH EVENTS: NextEvent.CHANGE NextEvent.INVOICE
         //
-        TestDryRunArguments dryRun = new TestDryRunArguments("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null, SubscriptionEventType.CHANGE,
+        TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null, SubscriptionEventType.CHANGE,
                                                              subscription.getId(), subscription.getBundleId(), clock.getUTCNow(), null);
         Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(initialCreationDate.toLocalDate(), null, InvoiceItemType.FIXED, new BigDecimal("0")));
@@ -173,7 +174,7 @@ public class TestIntegration extends TestIntegrationBase {
         setDateAndCheckForCompletion(new DateTime(2012, 3, 1, 23, 59, 59, 0, testTimeZone));
 
         DateTime nextDate = clock.getUTCNow().plusDays(1);
-        dryRun = new TestDryRunArguments();
+        dryRun = new TestDryRunArguments(DryRunType.TARGET_DATE);
 
 
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 3, 2), new LocalDate(2012, 3, 31), InvoiceItemType.RECURRING, new BigDecimal("561.24")));
@@ -202,7 +203,7 @@ public class TestIntegration extends TestIntegrationBase {
 
 
         nextDate = clock.getUTCNow().plusDays(31);
-        dryRun = new TestDryRunArguments();
+        dryRun = new TestDryRunArguments(DryRunType.TARGET_DATE);
         dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), new LocalDate(nextDate, testTimeZone), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 3, 31), new LocalDate(2012, 4, 30), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
 
@@ -287,7 +288,7 @@ public class TestIntegration extends TestIntegrationBase {
         //
 
 
-        TestDryRunArguments dryRun = new TestDryRunArguments("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null, SubscriptionEventType.CHANGE,
+        TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null, SubscriptionEventType.CHANGE,
                                                              subscription.getId(), subscription.getBundleId(), null, null);
         try {
            invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
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..3a17e84 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
@@ -61,6 +61,7 @@ import org.killbill.billing.entitlement.api.EntitlementApiException;
 import org.killbill.billing.entitlement.api.SubscriptionApi;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.invoice.api.DryRunArguments;
+import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoicePaymentApi;
@@ -243,8 +244,6 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
     @Inject
     protected IDBI idbi;
 
-    @Inject
-    protected CacheControllerDispatcher controlCacheDispatcher;
 
     @Inject
     protected TestApiListener busHandler;
@@ -273,9 +272,6 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
         //Thread.currentThread().setContextClassLoader(null);
 
         log.debug("RESET TEST FRAMEWORK");
-
-        controlCacheDispatcher.clearAll();
-
         overdueConfigCache.loadDefaultOverdueConfig((OverdueConfig) null);
 
         clock.resetDeltaFromReality();
@@ -715,6 +711,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
 
     protected static class TestDryRunArguments implements DryRunArguments {
 
+        private final DryRunType dryRunType;
         private final PlanPhaseSpecifier spec;
         private final SubscriptionEventType action;
         private final UUID subscriptionId;
@@ -722,7 +719,8 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
         private final DateTime effectiveDate;
         private final BillingActionPolicy billingPolicy;
 
-        public TestDryRunArguments() {
+        public TestDryRunArguments(final DryRunType dryRunType) {
+            this.dryRunType = dryRunType;
             this.spec = null;
             this.action = null;
             this.subscriptionId = null;
@@ -731,7 +729,8 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
             this.billingPolicy = null;
         }
 
-        public TestDryRunArguments(final String productName,
+        public TestDryRunArguments(final DryRunType dryRunType,
+                                   final String productName,
                                    final ProductCategory category,
                                    final BillingPeriod billingPeriod,
                                    final String priceList,
@@ -741,6 +740,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                                    final UUID bundleId,
                                    final DateTime effectiveDate,
                                    final BillingActionPolicy billingPolicy) {
+            this.dryRunType = dryRunType;
             this.spec = new PlanPhaseSpecifier(productName, category, billingPeriod, priceList, phaseType);
             this.action = action;
             this.subscriptionId = subscriptionId;
@@ -750,6 +750,11 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
         }
 
         @Override
+        public DryRunType getDryRunType() {
+            return dryRunType;
+        }
+
+        @Override
         public PlanPhaseSpecifier getPlanPhaseSpecifier() {
             return spec;
         }
@@ -780,7 +785,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
         }
 
         @Override
-        public List<PlanPhasePriceOverride> getPlanPhasePriceoverrides() {
+        public List<PlanPhasePriceOverride> getPlanPhasePriceOverrides() {
             return null;
         }
     }
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
index 362c1c5..3d81d73 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
@@ -33,6 +33,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.DefaultEntitlement;
 import org.killbill.billing.invoice.api.DryRunArguments;
+import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.payment.api.Payment;
@@ -78,7 +79,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 6, 14), new LocalDate(2015, 7, 14), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
 
         // This will verify that the upcoming Phase is found and the invoice is generated at the right date, with correct items
-        DryRunArguments dryRun = new TestDryRunArguments();
+        DryRunArguments dryRun = new TestDryRunArguments(DryRunType.UPCOMING_INVOICE);
         Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
         invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
 
@@ -144,12 +145,12 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
         final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2014, 2, 1), new LocalDate(2015, 2, 1), InvoiceItemType.RECURRING, new BigDecimal("2399.95")));
 
-        DryRunArguments dryRun = new TestDryRunArguments();
+        DryRunArguments dryRun = new TestDryRunArguments(DryRunType.UPCOMING_INVOICE);
         Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
         invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
 
         busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT);
-        // 2014-1-2
+        // 2014-2-1
         clock.addDays(30);
         assertListenerStatus();
         invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, callContext, expectedInvoices);
@@ -184,7 +185,16 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
         invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, callContext, expectedInvoices);
         expectedInvoices.clear();
 
-        //
+
+        // We test first the next expected invoice for a specific subscription: We can see the targetDate is 2015-2-14 and not 2015-2-1
+        final DryRunArguments dryRunWIthSubscription = new TestDryRunArguments(DryRunType.UPCOMING_INVOICE, null, null, null, null, null, null, subscriptionMonthly.getId(), null, null, null);
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 2, 14), new LocalDate(2015, 3, 14), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+        dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRunWIthSubscription, callContext);
+        assertEquals(dryRunInvoice.getTargetDate(), new LocalDate(2015, 2, 14));
+        invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+        expectedInvoices.clear();
+
+        // Then we test first the next expected invoice at the account level
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 2, 1), new LocalDate(2016, 2, 1), InvoiceItemType.RECURRING, new BigDecimal("2399.95")));
         dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
         invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
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/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
index 3dc6b0e..0d21887 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
+import org.killbill.billing.invoice.api.DryRunType;
 import org.testng.annotations.Test;
 
 import org.killbill.billing.account.api.Account;
@@ -87,7 +88,7 @@ public class TestSubscription extends TestIntegrationBase {
                 new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 11), new LocalDate(2013, 5, 1), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-2334.20")),
                 new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 11), new LocalDate(2012, 5, 11), InvoiceItemType.CBA_ADJ, new BigDecimal("2164.88"), false /* Issue with test where created date for context is wrong*/));
 
-        TestDryRunArguments dryRun = new TestDryRunArguments(productName, ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
+        TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, productName, ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
                                                              SubscriptionEventType.CHANGE, bpEntitlement.getId(), bpEntitlement.getBundleId(), null, BillingActionPolicy.IMMEDIATE);
         Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, toBeChecked);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
index 7f2ecc6..0157fef 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
@@ -26,9 +26,9 @@ import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -303,7 +303,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
                     }
 
                     final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getBundleFromId(bundleId, contextWithValidAccountRecordId);
-                    final Account account = accountApi.getAccountById(bundle.getAccountId(), contextWithValidAccountRecordId);
+                    final ImmutableAccountData account = accountApi.getImmutableAccountDataById(bundle.getAccountId(), contextWithValidAccountRecordId);
                     final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
                     final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), baseSubscription.getStartDate(), contextWithValidAccountRecordId);
 
@@ -358,7 +358,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
                 try {
                     final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
                     final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getBundleFromId(bundleId, contextWithValidAccountRecordId);
-                    final Account account = accountApi.getAccountById(bundle.getAccountId(), contextWithValidAccountRecordId);
+                    final ImmutableAccountData account = accountApi.getImmutableAccountDataById(bundle.getAccountId(), contextWithValidAccountRecordId);
                     final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
 
                     final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), baseSubscription.getStartDate(), contextWithValidAccountRecordId);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
index 3b0b63b..7d6272c 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
@@ -18,12 +18,10 @@ package org.killbill.billing.entitlement.api;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
-import org.joda.time.Interval;
 import org.joda.time.LocalDate;
-
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.clock.Clock;
 import org.killbill.clock.ClockUtil;
@@ -40,7 +38,7 @@ public class EntitlementDateHelper {
 
     public DateTime fromLocalDateAndReferenceTime(final LocalDate requestedDate, final DateTime referenceDateTime, final InternalTenantContext callContext) throws EntitlementApiException {
         try {
-            final Account account = accountApi.getAccountByRecordId(callContext.getAccountRecordId(), callContext);
+            final ImmutableAccountData account = accountApi.getImmutableAccountDataByRecordId(callContext.getAccountRecordId(), callContext);
             return ClockUtil.computeDateTimeWithUTCReferenceTime(requestedDate, referenceDateTime.toDateTime(DateTimeZone.UTC).toLocalTime(), account.getTimeZone(), clock);
         } catch (AccountApiException e) {
             throw new EntitlementApiException(e);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultAccountEntitlements.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultAccountEntitlements.java
index f86b587..deca457 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultAccountEntitlements.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultAccountEntitlements.java
@@ -20,7 +20,7 @@ import java.util.Collection;
 import java.util.Map;
 import java.util.UUID;
 
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.entitlement.AccountEntitlements;
 import org.killbill.billing.entitlement.AccountEventsStreams;
 import org.killbill.billing.entitlement.api.Entitlement;
@@ -37,7 +37,7 @@ public class DefaultAccountEntitlements implements AccountEntitlements {
     }
 
     @Override
-    public Account getAccount() {
+    public ImmutableAccountData getAccount() {
         return accountEventsStreams.getAccount();
     }
 
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultAccountEventsStreams.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultAccountEventsStreams.java
index df46e81..d1b09a8 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultAccountEventsStreams.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultAccountEventsStreams.java
@@ -21,7 +21,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.entitlement.AccountEventsStreams;
 import org.killbill.billing.entitlement.EventsStream;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
@@ -31,11 +31,11 @@ import com.google.common.collect.ImmutableMap;
 
 public class DefaultAccountEventsStreams implements AccountEventsStreams {
 
-    private final Account account;
+    private final ImmutableAccountData account;
     private final Map<UUID, Collection<EventsStream>> eventsStreams;
     private final Map<UUID, SubscriptionBaseBundle> bundles = new HashMap<UUID, SubscriptionBaseBundle>();
 
-    public DefaultAccountEventsStreams(final Account account,
+    public DefaultAccountEventsStreams(final ImmutableAccountData account,
                                        final Iterable<SubscriptionBaseBundle> bundles,
                                        final Map<UUID, Collection<EventsStream>> eventsStreams) {
         this.account = account;
@@ -45,12 +45,12 @@ public class DefaultAccountEventsStreams implements AccountEventsStreams {
         }
     }
 
-    public DefaultAccountEventsStreams(final Account account) {
+    public DefaultAccountEventsStreams(final ImmutableAccountData account) {
         this(account, ImmutableList.<SubscriptionBaseBundle>of(), ImmutableMap.<UUID, Collection<EventsStream>>of());
     }
 
     @Override
-    public Account getAccount() {
+    public ImmutableAccountData getAccount() {
         return account;
     }
 
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
index 1457e63..cef565e 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
@@ -21,12 +21,9 @@ import java.util.List;
 
 import javax.annotation.Nullable;
 
-import org.skife.jdbi.v2.IDBI;
-
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.ProductCategory;
-import org.killbill.clock.Clock;
 import org.killbill.billing.entitlement.EventsStream;
 import org.killbill.billing.entitlement.api.BlockingState;
 import org.killbill.billing.entitlement.api.BlockingStateType;
@@ -37,6 +34,8 @@ import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.clock.Clock;
+import org.skife.jdbi.v2.IDBI;
 
 import com.google.common.collect.ImmutableList;
 
@@ -57,22 +56,20 @@ public class OptimizedProxyBlockingStateDao extends ProxyBlockingStateDao {
      * <p/>
      * This is a special method for EventsStreamBuilder to save some DAO calls.
      *
-     * @param subscriptionBlockingStatesOnDisk
-     *                                  blocking states on disk for that subscription
-     * @param allBlockingStatesOnDiskForAccount
-     *                                  all blocking states on disk for that account
-     * @param account                   account associated with the subscription
-     * @param bundle                    bundle associated with the subscription
-     * @param baseSubscription          base subscription (ProductCategory.BASE) associated with that bundle
-     * @param subscription              subscription for which to build blocking states
-     * @param allSubscriptionsForBundle all subscriptions associated with that bundle
-     * @param context                   call context
+     * @param subscriptionBlockingStatesOnDisk  blocking states on disk for that subscription
+     * @param allBlockingStatesOnDiskForAccount all blocking states on disk for that account
+     * @param account                           account associated with the subscription
+     * @param bundle                            bundle associated with the subscription
+     * @param baseSubscription                  base subscription (ProductCategory.BASE) associated with that bundle
+     * @param subscription                      subscription for which to build blocking states
+     * @param allSubscriptionsForBundle         all subscriptions associated with that bundle
+     * @param context                           call context
      * @return blocking states for that subscription
      * @throws EntitlementApiException
      */
     public List<BlockingState> getBlockingHistory(final List<BlockingState> subscriptionBlockingStatesOnDisk,
                                                   final List<BlockingState> allBlockingStatesOnDiskForAccount,
-                                                  final Account account,
+                                                  final ImmutableAccountData account,
                                                   final SubscriptionBaseBundle bundle,
                                                   @Nullable final SubscriptionBase baseSubscription,
                                                   final SubscriptionBase subscription,
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
index 192d301..23795b6 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
@@ -27,7 +27,7 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.Product;
@@ -55,7 +55,7 @@ import com.google.common.collect.Iterables;
 
 public class DefaultEventsStream implements EventsStream {
 
-    private final Account account;
+    private final ImmutableAccountData account;
     private final SubscriptionBaseBundle bundle;
     // All blocking states for the account, associated bundle or subscription
     private final List<BlockingState> blockingStates;
@@ -80,7 +80,7 @@ public class DefaultEventsStream implements EventsStream {
     private BlockingState entitlementCancelEvent;
     private EntitlementState entitlementState;
 
-    public DefaultEventsStream(final Account account, final SubscriptionBaseBundle bundle,
+    public DefaultEventsStream(final ImmutableAccountData account, final SubscriptionBaseBundle bundle,
                                final List<BlockingState> blockingStates, final BlockingChecker blockingChecker,
                                @Nullable final SubscriptionBase baseSubscription, final SubscriptionBase subscription,
                                final List<SubscriptionBase> allSubscriptionsForBundle, final InternalTenantContext contextWithValidAccountRecordId, final DateTime utcNow) {
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
index 8bb42d5..afd51c8 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
@@ -29,9 +29,9 @@ import javax.inject.Inject;
 import javax.inject.Singleton;
 
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.AccountEventsStreams;
@@ -123,9 +123,9 @@ public class EventsStreamBuilder {
     // Special signature for ProxyBlockingStateDao to save a DAO call
     public AccountEventsStreams buildForAccount(final Map<UUID, List<SubscriptionBase>> subscriptions, final InternalTenantContext internalTenantContext) throws EntitlementApiException {
         // Retrieve the account
-        final Account account;
+        final ImmutableAccountData account;
         try {
-            account = accountInternalApi.getAccountByRecordId(internalTenantContext.getAccountRecordId(), internalTenantContext);
+            account = accountInternalApi.getImmutableAccountDataByRecordId(internalTenantContext.getAccountRecordId(), internalTenantContext);
         } catch (AccountApiException e) {
             throw new EntitlementApiException(e);
         }
@@ -229,9 +229,9 @@ public class EventsStreamBuilder {
             throw new EntitlementApiException(e);
         }
 
-        final Account account;
+        final ImmutableAccountData account;
         try {
-            account = accountInternalApi.getAccountById(bundle.getAccountId(), internalTenantContext);
+            account = accountInternalApi.getImmutableAccountDataById(bundle.getAccountId(), internalTenantContext);
         } catch (AccountApiException e) {
             throw new EntitlementApiException(e);
         }
@@ -244,7 +244,7 @@ public class EventsStreamBuilder {
 
     // Special signature for OptimizedProxyBlockingStateDao to save some DAO calls
     public EventsStream buildForEntitlement(final List<BlockingState> blockingStatesForAccount,
-                                            final Account account,
+                                            final ImmutableAccountData account,
                                             final SubscriptionBaseBundle bundle,
                                             final SubscriptionBase baseSubscription,
                                             final List<SubscriptionBase> allSubscriptionsForBundle,
@@ -253,7 +253,7 @@ public class EventsStreamBuilder {
     }
 
     private EventsStream buildForEntitlement(final List<BlockingState> blockingStatesForAccount,
-                                             final Account account,
+                                             final ImmutableAccountData account,
                                              final SubscriptionBaseBundle bundle,
                                              @Nullable final SubscriptionBase baseSubscription,
                                              final SubscriptionBase subscription,
@@ -312,7 +312,7 @@ public class EventsStreamBuilder {
         return buildForEntitlement(account, bundle, baseSubscription, subscription, allSubscriptionsForBundle, blockingStates, internalTenantContext);
     }
 
-    private EventsStream buildForEntitlement(final Account account,
+    private EventsStream buildForEntitlement(final ImmutableAccountData account,
                                              final SubscriptionBaseBundle bundle,
                                              @Nullable final SubscriptionBase baseSubscription,
                                              final SubscriptionBase subscription,
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
index 9a586a1..ae889c9 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
@@ -42,6 +42,7 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
 
         account = Mockito.mock(Account.class);
         Mockito.when(accountInternalApi.getAccountByRecordId(Mockito.anyLong(), Mockito.<InternalTenantContext>any())).thenReturn(account);
+        Mockito.when(accountInternalApi.getImmutableAccountDataByRecordId(Mockito.anyLong(), Mockito.<InternalTenantContext>any())).thenReturn(account);
         dateHelper = new EntitlementDateHelper(accountInternalApi, clock);
         clock.resetDeltaFromReality();;
     }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java
index 47b0034..ba2227e 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java
@@ -21,9 +21,8 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications;
 import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications.SubscriptionNotification;
 import org.killbill.billing.util.timezone.DateAndTimeZoneContext;
@@ -69,9 +68,9 @@ public class DefaultInvoiceMigrationApi implements InvoiceMigrationApi {
 
     @Override
     public UUID createMigrationInvoice(final UUID accountId, final LocalDate targetDate, final BigDecimal balance, final Currency currency, final CallContext context) {
-        Account account;
+        ImmutableAccountData account;
         try {
-            account = accountUserApi.getAccountById(accountId, internalCallContextFactory.createInternalTenantContext(accountId, context));
+            account = accountUserApi.getImmutableAccountDataById(accountId, internalCallContextFactory.createInternalTenantContext(accountId, context));
         } catch (AccountApiException e) {
             log.warn("Unable to find account for id {}", accountId);
             return null;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 42d8f7c..dfe060f 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -35,6 +35,7 @@ import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Currency;
@@ -205,9 +206,9 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
                                             final CallContext context) throws InvoiceApiException {
         final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(accountId, context);
 
-        final Account account;
+        final ImmutableAccountData account;
         try {
-            account = accountUserApi.getAccountById(accountId, internalContext);
+            account = accountUserApi.getImmutableAccountDataById(accountId, internalContext);
         } catch (final AccountApiException e) {
             throw new InvoiceApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, e.toString());
         }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
index 64f07ba..c9a290a 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -18,9 +18,7 @@
 
 package org.killbill.billing.invoice.generator;
 
-import java.math.BigDecimal;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -30,13 +28,12 @@ import javax.annotation.Nullable;
 import org.joda.time.LocalDate;
 import org.joda.time.Months;
 import org.killbill.billing.ErrorCode;
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
-import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates;
 import org.killbill.billing.invoice.model.DefaultInvoice;
 import org.killbill.billing.junction.BillingEventSet;
@@ -66,7 +63,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
      * adjusts target date to the maximum invoice target date, if future invoices exist
      */
     @Override
-    public InvoiceWithMetadata generateInvoice(final Account account, @Nullable final BillingEventSet events,
+    public InvoiceWithMetadata generateInvoice(final ImmutableAccountData account, @Nullable final BillingEventSet events,
                                                @Nullable final List<Invoice> existingInvoices,
                                                final LocalDate targetDate,
                                                final Currency targetCurrency, final InternalCallContext context) throws InvoiceApiException {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
index 390afca..940f746 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
@@ -28,7 +28,7 @@ import javax.annotation.Nullable;
 
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.BillingPeriod;
@@ -63,7 +63,7 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
     public FixedAndRecurringInvoiceItemGenerator() {
     }
 
-    public List<InvoiceItem> generateItems(final Account account, final UUID invoiceId, final BillingEventSet eventSet,
+    public List<InvoiceItem> generateItems(final ImmutableAccountData account, final UUID invoiceId, final BillingEventSet eventSet,
                                            @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
                                            final Currency targetCurrency, Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
                                            final InternalCallContext internalCallContext) throws InvoiceApiException {
@@ -165,15 +165,15 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
 
                     if (rate != null) {
                         final BigDecimal amount = KillBillMoney.of(itemDatum.getNumberOfCycles().multiply(rate), currency);
-                            final RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(invoiceId,
-                                                                                                accountId,
-                                                                                                thisEvent.getSubscription().getBundleId(),
-                                                                                                thisEvent.getSubscription().getId(),
-                                                                                                thisEvent.getPlan().getName(),
-                                                                                                thisEvent.getPlanPhase().getName(),
-                                                                                                itemDatum.getStartDate(), itemDatum.getEndDate(),
-                                                                                                amount, rate, currency);
-                            items.add(recurringItem);
+                        final RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(invoiceId,
+                                                                                            accountId,
+                                                                                            thisEvent.getSubscription().getBundleId(),
+                                                                                            thisEvent.getSubscription().getId(),
+                                                                                            thisEvent.getPlan().getName(),
+                                                                                            thisEvent.getPlanPhase().getName(),
+                                                                                            itemDatum.getStartDate(), itemDatum.getEndDate(),
+                                                                                            amount, rate, currency);
+                        items.add(recurringItem);
                     }
                 }
                 updatePerSubscriptionNextNotificationDate(thisEvent.getSubscription().getId(), itemDataWithNextBillingCycleDate.getNextBillingCycleDate(), items, billingMode, perSubscriptionFutureNotificationDate);
@@ -190,7 +190,6 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
         return items;
     }
 
-
     private void updatePerSubscriptionNextNotificationDate(final UUID subscriptionId, final LocalDate nextBillingCycleDate, final List<InvoiceItem> newProposedItems, final BillingMode billingMode, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
 
         LocalDate nextNotificationDate = null;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
index 09f41ee..e513a00 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
@@ -17,13 +17,12 @@
 package org.killbill.billing.invoice.generator;
 
 import java.util.List;
-import java.util.UUID;
 
 import javax.annotation.Nullable;
 
 import org.joda.time.LocalDate;
 
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.Invoice;
@@ -31,6 +30,6 @@ import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.junction.BillingEventSet;
 
 public interface InvoiceGenerator {
-    InvoiceWithMetadata generateInvoice(Account account, @Nullable BillingEventSet events, @Nullable List<Invoice> existingInvoices,
+    InvoiceWithMetadata generateInvoice(ImmutableAccountData account,  @Nullable BillingEventSet events, @Nullable List<Invoice> existingInvoices,
                                         LocalDate targetDate, Currency targetCurrency, final InternalCallContext context) throws InvoiceApiException;
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
index 22b0bac..d9b3090 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
@@ -24,7 +24,7 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.LocalDate;
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.Invoice;
@@ -35,7 +35,7 @@ import org.killbill.billing.junction.BillingEventSet;
 
 public abstract class InvoiceItemGenerator {
 
-    public abstract List<InvoiceItem> generateItems(final Account account, final UUID invoiceId, final BillingEventSet eventSet,
+    public abstract List<InvoiceItem> generateItems(final ImmutableAccountData account, final UUID invoiceId, final BillingEventSet eventSet,
                                                     @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
                                                     final Currency targetCurrency, Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
                                                     final InternalCallContext context) throws InvoiceApiException;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
index 8654de5..b19e774 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
@@ -29,7 +29,7 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.CatalogApiException;
@@ -71,7 +71,7 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
 
 
     @Override
-    public List<InvoiceItem> generateItems(final Account account,
+    public List<InvoiceItem> generateItems(final ImmutableAccountData account,
                                            final UUID invoiceId,
                                            final BillingEventSet eventSet,
                                            @Nullable final List<Invoice> existingInvoices,
@@ -94,7 +94,7 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
             while (events.hasNext()) {
                 final BillingEvent event = events.next();
                 // Skip events that are posterior to the targetDate
-                final LocalDate eventLocalEffectiveDate = new LocalDate(event.getEffectiveDate(), event.getAccount().getTimeZone());
+                final LocalDate eventLocalEffectiveDate = new LocalDate(event.getEffectiveDate(), account.getTimeZone());
                 if (eventLocalEffectiveDate.isAfter(targetDate)) {
                     continue;
                 }
@@ -118,7 +118,7 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
 
                 final UUID subscriptionId = event.getSubscription().getId();
                 if (curSubscriptionId != null && !curSubscriptionId.equals(subscriptionId)) {
-                    final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(invoiceId, curEvents, rawUsageOptimizerResult.getRawUsage(), targetDate, rawUsageOptimizerResult.getRawUsageStartDate());
+                    final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(account.getId(), invoiceId, curEvents, rawUsageOptimizerResult.getRawUsage(), targetDate, rawUsageOptimizerResult.getRawUsageStartDate());
                     final List<InvoiceItem> consumableInUsageArrearItems = perSubscriptionConsumableInArrearUsageItems.get(curSubscriptionId);
 
                     final SubscriptionConsumableInArrearItemsAndNextNotificationDate subscriptionResult = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of());
@@ -131,7 +131,7 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
                 curEvents.add(event);
             }
             if (curSubscriptionId != null) {
-                final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(invoiceId, curEvents, rawUsageOptimizerResult.getRawUsage(), targetDate, rawUsageOptimizerResult.getRawUsageStartDate());
+                final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(account.getId(), invoiceId, curEvents, rawUsageOptimizerResult.getRawUsage(), targetDate, rawUsageOptimizerResult.getRawUsageStartDate());
                 final List<InvoiceItem> consumableInUsageArrearItems = perSubscriptionConsumableInArrearUsageItems.get(curSubscriptionId);
 
                 final SubscriptionConsumableInArrearItemsAndNextNotificationDate subscriptionResult = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of());
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index 4460632..49ec8d8 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -36,6 +37,7 @@ import org.killbill.billing.ErrorCode;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -52,6 +54,7 @@ import org.killbill.billing.events.InvoiceNotificationInternalEvent;
 import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications.SubscriptionNotification;
 import org.killbill.billing.invoice.api.DefaultInvoiceService;
 import org.killbill.billing.invoice.api.DryRunArguments;
+import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
@@ -74,6 +77,7 @@ import org.killbill.billing.invoice.model.InvoiceItemFactory;
 import org.killbill.billing.invoice.model.RecurringInvoiceItem;
 import org.killbill.billing.invoice.notification.DefaultNextBillingDateNotifier;
 import org.killbill.billing.invoice.notification.NextBillingDateNotificationKey;
+import org.killbill.billing.junction.BillingEvent;
 import org.killbill.billing.junction.BillingEventSet;
 import org.killbill.billing.junction.BillingInternalApi;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
@@ -112,10 +116,9 @@ public class InvoiceDispatcher {
 
     private static final Logger log = LoggerFactory.getLogger(InvoiceDispatcher.class);
 
-
     private static final Ordering<DateTime> UPCOMING_NOTIFICATION_DATE_ORDERING = Ordering.natural();
     private final static Joiner JOINER_COMMA = Joiner.on(",");
-    private static final NullDryRunArguments NULL_DRY_RUN_ARGUMENTS = new NullDryRunArguments();
+    private static final TargetDateDryRunArguments TARGET_DATE_DRY_RUN_ARGUMENTS = new TargetDateDryRunArguments();
 
     private final InvoiceGenerator generator;
     private final BillingInternalApi billingApi;
@@ -191,7 +194,7 @@ public class InvoiceDispatcher {
                 return null;
             }
             final UUID accountId = subscriptionApi.getAccountIdFromSubscriptionId(subscriptionId, context);
-            final DryRunArguments dryRunArguments = dryRunForNotification ? NULL_DRY_RUN_ARGUMENTS : null;
+            final DryRunArguments dryRunArguments = dryRunForNotification ? TARGET_DATE_DRY_RUN_ARGUMENTS : null;
 
             return processAccount(accountId, targetDate, dryRunArguments, context);
         } catch (final SubscriptionBaseApiException e) {
@@ -201,7 +204,7 @@ public class InvoiceDispatcher {
         }
     }
 
-    public Invoice processAccount(final UUID accountId,  @Nullable final DateTime targetDate,
+    public Invoice processAccount(final UUID accountId, @Nullable final DateTime targetDate,
                                   @Nullable final DryRunArguments dryRunArguments, final InternalCallContext context) throws InvoiceApiException {
         GlobalLock lock = null;
         try {
@@ -225,17 +228,22 @@ public class InvoiceDispatcher {
 
         final boolean isDryRun = dryRunArguments != null;
         // A null inputTargetDateTime is only allowed in dryRun mode to have the system compute it
-        Preconditions.checkArgument(inputTargetDateTime != null || isDryRun, "inputTargetDateTime is required in non dryRun mode");
+        Preconditions.checkArgument(inputTargetDateTime != null ||
+                                    (dryRunArguments != null && DryRunType.UPCOMING_INVOICE.equals(dryRunArguments.getDryRunType())), "inputTargetDateTime is required in non dryRun mode");
         try {
             // Make sure to first set the BCD if needed then get the account object (to have the BCD set)
             final BillingEventSet billingEvents = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId, dryRunArguments, context);
             if (billingEvents.isEmpty()) {
                 return null;
             }
-            final List<DateTime> candidateDateTimes = (inputTargetDateTime != null) ? ImmutableList.of(inputTargetDateTime) : getUpcomingInvoiceCandidateDates(context);
+            final Iterable<UUID> filteredSubscriptionIdsForDryRun = getFilteredSubscriptionIdsForDryRun(dryRunArguments, billingEvents);
+            final List<DateTime> candidateDateTimes = (inputTargetDateTime != null) ?
+                                                      ImmutableList.of(inputTargetDateTime) :
+                                                      getUpcomingInvoiceCandidateDates(filteredSubscriptionIdsForDryRun, context);
             for (final DateTime curTargetDateTime : candidateDateTimes) {
                 final Invoice invoice = processAccountWithLockAndInputTargetDate(accountId, curTargetDateTime, billingEvents, isDryRun, context);
                 if (invoice != null) {
+                    filterInvoiceItemsForDryRun(filteredSubscriptionIdsForDryRun, invoice);
                     return invoice;
                 }
             }
@@ -246,10 +254,49 @@ public class InvoiceDispatcher {
         }
     }
 
+    private void filterInvoiceItemsForDryRun(final Iterable<UUID> filteredSubscriptionIdsForDryRun, final Invoice invoice) {
+        if (!filteredSubscriptionIdsForDryRun.iterator().hasNext()) {
+            return;
+        }
+
+        final Iterator<InvoiceItem> it = invoice.getInvoiceItems().iterator();
+        while (it.hasNext()) {
+            final InvoiceItem cur = it.next();
+            if (!Iterables.contains(filteredSubscriptionIdsForDryRun, cur.getSubscriptionId())) {
+                it.remove();
+            }
+        }
+    }
+
+    private Iterable<UUID> getFilteredSubscriptionIdsForDryRun(@Nullable final DryRunArguments dryRunArguments, final BillingEventSet billingEvents) {
+        if (dryRunArguments == null ||
+            !dryRunArguments.getDryRunType().equals(DryRunType.UPCOMING_INVOICE) ||
+            (dryRunArguments.getSubscriptionId() == null && dryRunArguments.getBundleId() == null)) {
+            return ImmutableList.<UUID>of();
+        }
+
+        if (dryRunArguments.getSubscriptionId() != null) {
+            return ImmutableList.of(dryRunArguments.getSubscriptionId());
+        }
+
+        return Iterables.transform(Iterables.filter(billingEvents, new Predicate<BillingEvent>() {
+            @Override
+            public boolean apply(final BillingEvent input) {
+                return input.getSubscription().getBundleId().equals(dryRunArguments.getBundleId());
+            }
+        }), new Function<BillingEvent, UUID>() {
+            @Override
+            public UUID apply(final BillingEvent input) {
+                return input.getSubscription().getId();
+            }
+        });
+    }
+
     private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final DateTime targetDateTime,
                                                              final BillingEventSet billingEvents, final boolean isDryRun, final InternalCallContext context) throws InvoiceApiException {
         try {
-            final Account account = accountApi.getAccountById(accountId, context);
+            final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
+
             final DateAndTimeZoneContext dateAndTimeZoneContext = new DateAndTimeZoneContext(billingEvents.iterator().next().getEffectiveDate(), account.getTimeZone(), clock);
 
             final List<Invoice> invoices = billingEvents.isAccountAutoInvoiceOff() ?
@@ -300,13 +347,11 @@ public class InvoiceDispatcher {
             final CallContext callContext = buildCallContext(context);
             invoice.addInvoiceItems(invoicePluginDispatcher.getAdditionalInvoiceItems(invoice, callContext));
 
-
-
             if (!isDryRun) {
 
                 // Compute whether this is a new invoice object (or just some adjustments on an existing invoice), and extract invoiceIds for later use
                 final Set<UUID> uniqueInvoiceIds = getUniqueInvoiceIds(invoice);
-                final boolean  isRealInvoiceWithItems = uniqueInvoiceIds.remove(invoice.getId());
+                final boolean isRealInvoiceWithItems = uniqueInvoiceIds.remove(invoice.getId());
                 final Set<UUID> adjustedUniqueOtherInvoiceId = uniqueInvoiceIds;
 
                 logInvoiceWithItems(account, invoice, targetDate, adjustedUniqueOtherInvoiceId, isRealInvoiceWithItems);
@@ -320,7 +365,6 @@ public class InvoiceDispatcher {
 
                 final boolean isRealInvoiceWithNonEmptyItems = isThereAnyItemsLeft ? isRealInvoiceWithItems : false;
 
-
                 setChargedThroughDates(dateAndTimeZoneContext, invoice.getInvoiceItems(FixedPriceInvoiceItem.class), invoice.getInvoiceItems(RecurringInvoiceItem.class), context);
 
                 // TODO we should send bus events when we commit the ionvoice on disk in commitInvoice
@@ -338,7 +382,6 @@ public class InvoiceDispatcher {
         }
     }
 
-
     private FutureAccountNotifications createNextFutureNotificationDate(final InvoiceWithMetadata invoiceWithMetadata, final DateAndTimeZoneContext dateAndTimeZoneContext, final InternalCallContext context) {
 
         final Map<UUID, List<SubscriptionNotification>> result = new HashMap<UUID, List<SubscriptionNotification>>();
@@ -384,12 +427,12 @@ public class InvoiceDispatcher {
 
     private Iterable<InvoiceItemModelDao> transformToInvoiceModelDao(final List<InvoiceItem> invoiceItems) {
         return Iterables.transform(invoiceItems,
-                            new Function<InvoiceItem, InvoiceItemModelDao>() {
-                                @Override
-                                public InvoiceItemModelDao apply(final InvoiceItem input) {
-                                    return new InvoiceItemModelDao(input);
-                                }
-                            });
+                                   new Function<InvoiceItem, InvoiceItemModelDao>() {
+                                       @Override
+                                       public InvoiceItemModelDao apply(final InvoiceItem input) {
+                                           return new InvoiceItemModelDao(input);
+                                       }
+                                   });
     }
 
     private Set<UUID> getUniqueInvoiceIds(final Invoice invoice) {
@@ -404,7 +447,7 @@ public class InvoiceDispatcher {
         return uniqueInvoiceIds;
     }
 
-    private void logInvoiceWithItems(final Account account, final Invoice invoice, final LocalDate targetDate, final Set<UUID> adjustedUniqueOtherInvoiceId, final boolean isRealInvoiceWithItems) {
+    private void logInvoiceWithItems(final ImmutableAccountData account, final Invoice invoice, final LocalDate targetDate, final Set<UUID> adjustedUniqueOtherInvoiceId, final boolean isRealInvoiceWithItems) {
         final StringBuilder tmp = new StringBuilder();
         if (isRealInvoiceWithItems) {
             tmp.append(String.format("Generated invoice %s with %d items for accountId %s and targetDate %s:\n", invoice.getId(), invoice.getNumberOfItems(), account.getId(), targetDate));
@@ -419,8 +462,7 @@ public class InvoiceDispatcher {
         log.info(tmp.toString());
     }
 
-
-    private boolean commitInvoiceAndSetFutureNotifications(final Account account, final InvoiceModelDao invoiceModelDao,
+    private boolean commitInvoiceAndSetFutureNotifications(final ImmutableAccountData account, final InvoiceModelDao invoiceModelDao,
                                                            final Iterable<InvoiceItemModelDao> invoiceItemModelDaos,
                                                            final FutureAccountNotifications futureAccountNotifications,
                                                            boolean isRealInvoiceWithItems, final InternalCallContext context) throws SubscriptionBaseApiException, InvoiceApiException {
@@ -442,7 +484,7 @@ public class InvoiceDispatcher {
         return isThereAnyItemsLeft;
     }
 
-    private void postEvents(final Account account, final Invoice invoice, final Set<UUID> adjustedUniqueOtherInvoiceId, final boolean isRealInvoiceWithNonEmptyItems, final InternalCallContext context) {
+    private void postEvents(final ImmutableAccountData account, final Invoice invoice, final Set<UUID> adjustedUniqueOtherInvoiceId, final boolean isRealInvoiceWithNonEmptyItems, final InternalCallContext context) {
 
         final List<InvoiceInternalEvent> events = new ArrayList<InvoiceInternalEvent>();
         if (isRealInvoiceWithNonEmptyItems) {
@@ -460,15 +502,18 @@ public class InvoiceDispatcher {
         }
     }
 
-    private void notifyAccountIfEnabled(final Account account, final Invoice invoice, final boolean isRealInvoiceWithNonEmptyItems, final InternalCallContext context) throws InvoiceApiException {
-        if (account.isNotifiedForInvoices() && isRealInvoiceWithNonEmptyItems) {
+    private void notifyAccountIfEnabled(final ImmutableAccountData account, final Invoice invoice, final boolean isRealInvoiceWithNonEmptyItems, final InternalCallContext context) throws InvoiceApiException, AccountApiException {
+        // Ideally we would retrieve the cached version, all the invoice code has been modified to only use ImmutableAccountData, except for the
+        // isNotifiedForInvoice piece that should probably live outside of invoice code anyways... (see https://github.com/killbill/killbill-email-notifications-plugin)
+        final Account fullAccount = accountApi.getAccountById(account.getId(), context);
+
+        if (fullAccount.isNotifiedForInvoices() && isRealInvoiceWithNonEmptyItems) {
             // Need to re-hydrate the invoice object to get the invoice number (record id)
             // API_FIX InvoiceNotifier public API?
-            invoiceNotifier.notify(account, new DefaultInvoice(invoiceDao.getById(invoice.getId(), context)), buildTenantContext(context));
+            invoiceNotifier.notify(fullAccount, new DefaultInvoice(invoiceDao.getById(invoice.getId(), context)), buildTenantContext(context));
         }
     }
 
-
     private InvoiceItem computeCBAOnExistingInvoice(final Invoice invoice, final InternalCallContext context) throws InvoiceApiException {
         // Transformation to Invoice -> InvoiceModelDao
         final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
@@ -558,7 +603,6 @@ public class InvoiceDispatcher {
             private final DateTime effectiveDate;
             private final boolean isForNotificationTrigger;
 
-
             public SubscriptionNotification(final DateTime effectiveDate, final boolean isForNotificationTrigger) {
                 this.effectiveDate = effectiveDate;
                 this.isForNotificationTrigger = isForNotificationTrigger;
@@ -574,30 +618,31 @@ public class InvoiceDispatcher {
         }
     }
 
-    private List<DateTime> getUpcomingInvoiceCandidateDates(final InternalCallContext internalCallContext) {
-        final Iterable<DateTime> nextScheduledInvoiceDates = getNextScheduledInvoiceEffectiveDate(internalCallContext);
+    private List<DateTime> getUpcomingInvoiceCandidateDates(final Iterable<UUID> filteredSubscriptionIds, final InternalCallContext internalCallContext) {
+        final Iterable<DateTime> nextScheduledInvoiceDates = getNextScheduledInvoiceEffectiveDate(filteredSubscriptionIds, internalCallContext);
         final Iterable<DateTime> nextScheduledSubscriptionsEventDates = subscriptionApi.getFutureNotificationsForAccount(internalCallContext);
         Iterables.concat(nextScheduledInvoiceDates, nextScheduledSubscriptionsEventDates);
         return UPCOMING_NOTIFICATION_DATE_ORDERING.sortedCopy(Iterables.concat(nextScheduledInvoiceDates, nextScheduledSubscriptionsEventDates));
     }
 
-    private Iterable<DateTime> getNextScheduledInvoiceEffectiveDate(final InternalCallContext internalCallContext) {
+    private Iterable<DateTime> getNextScheduledInvoiceEffectiveDate(final Iterable<UUID> filteredSubscriptionIds, final InternalCallContext internalCallContext) {
         try {
             final NotificationQueue notificationQueue = notificationQueueService.getNotificationQueue(DefaultInvoiceService.INVOICE_SERVICE_NAME,
                                                                                                       DefaultNextBillingDateNotifier.NEXT_BILLING_DATE_NOTIFIER_QUEUE);
             final List<NotificationEventWithMetadata<NextBillingDateNotificationKey>> futureNotifications = notificationQueue.getFutureNotificationForSearchKeys(internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
 
-            final Iterable<NotificationEventWithMetadata<NextBillingDateNotificationKey>> filtered = Iterables.filter(futureNotifications, new Predicate<NotificationEventWithMetadata<NextBillingDateNotificationKey>>() {
+            final Iterable<NotificationEventWithMetadata<NextBillingDateNotificationKey>> allUpcomingEvents = Iterables.filter(futureNotifications, new Predicate<NotificationEventWithMetadata<NextBillingDateNotificationKey>>() {
                 @Override
                 public boolean apply(@Nullable final NotificationEventWithMetadata<NextBillingDateNotificationKey> input) {
+                    final boolean isEventForSubscription = !filteredSubscriptionIds.iterator().hasNext() || Iterables.contains(filteredSubscriptionIds, input.getEvent().getUuidKey());
 
                     final boolean isEventDryRunForNotifications = input.getEvent().isDryRunForInvoiceNotification() != null ?
                                                                   input.getEvent().isDryRunForInvoiceNotification() : false;
-                    return !isEventDryRunForNotifications;
+                    return isEventForSubscription && !isEventDryRunForNotifications;
                 }
             });
 
-            return Iterables.transform(filtered, new Function<NotificationEventWithMetadata<NextBillingDateNotificationKey>, DateTime>() {
+            return Iterables.transform(allUpcomingEvents, new Function<NotificationEventWithMetadata<NextBillingDateNotificationKey>, DateTime>() {
                 @Nullable
                 @Override
                 public DateTime apply(@Nullable final NotificationEventWithMetadata<NextBillingDateNotificationKey> input) {
@@ -609,7 +654,12 @@ public class InvoiceDispatcher {
         }
     }
 
-    private final static class NullDryRunArguments implements DryRunArguments {
+    private final static class TargetDateDryRunArguments implements DryRunArguments {
+
+        @Override
+        public DryRunType getDryRunType() {
+            return DryRunType.TARGET_DATE;
+        }
 
         @Override
         public PlanPhaseSpecifier getPlanPhaseSpecifier() {
@@ -640,9 +690,8 @@ public class InvoiceDispatcher {
         public BillingActionPolicy getBillingActionPolicy() {
             return null;
         }
-
         @Override
-        public List<PlanPhasePriceOverride> getPlanPhasePriceoverrides() {
+        public List<PlanPhasePriceOverride> getPlanPhasePriceOverrides() {
             return null;
         }
     }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
index 5095a1c..bdda28d 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
@@ -69,12 +69,14 @@ public class ContiguousIntervalConsumableInArrear {
     private final Set<String> unitTypes;
     private final List<RawUsage> rawSubscriptionUsage;
     private final LocalDate targetDate;
+    private final UUID accountId;
     private final UUID invoiceId;
     private final AtomicBoolean isBuilt;
     private final LocalDate rawUsageStartDate;
 
-    public ContiguousIntervalConsumableInArrear(final Usage usage, final UUID invoiceId, final List<RawUsage> rawSubscriptionUsage, final LocalDate targetDate, final LocalDate rawUsageStartDate) {
+    public ContiguousIntervalConsumableInArrear(final Usage usage, final UUID accountId, final UUID invoiceId, final List<RawUsage> rawSubscriptionUsage, final LocalDate targetDate, final LocalDate rawUsageStartDate) {
         this.usage = usage;
+        this.accountId = accountId;
         this.invoiceId = invoiceId;
         this.unitTypes = getConsumableInArrearUnitTypes(usage);
         this.rawSubscriptionUsage = rawSubscriptionUsage;
@@ -173,7 +175,7 @@ public class ContiguousIntervalConsumableInArrear {
         LocalDate prevDate = null;
         for (LocalDate curDate : transitionTimes) {
             if (prevDate != null) {
-                InvoiceItem item = new UsageInvoiceItem(invoiceId, getAccountId(), getBundleId(), getSubscriptionId(), getPlanName(),
+                InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
                                                         getPhaseName(), usage.getName(), prevDate, curDate, BigDecimal.ZERO, getCurrency());
                 result.add(item);
             }
@@ -201,7 +203,7 @@ public class ContiguousIntervalConsumableInArrear {
             if (!billedItems.iterator().hasNext() || billedUsage.compareTo(toBeBilledUsage) < 0) {
                 final BigDecimal amountToBill = toBeBilledUsage.subtract(billedUsage);
                 if (amountToBill.compareTo(BigDecimal.ZERO) > 0) {
-                    InvoiceItem item = new UsageInvoiceItem(invoiceId, getAccountId(), getBundleId(), getSubscriptionId(), getPlanName(),
+                    InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
                                                             getPhaseName(), usage.getName(), ru.getStart(), ru.getEnd(), amountToBill, getCurrency());
                     result.add(item);
                 }
@@ -403,9 +405,6 @@ public class ContiguousIntervalConsumableInArrear {
         return billingEvents.get(0).getBillCycleDayLocal();
     }
 
-    public UUID getAccountId() {
-        return billingEvents.get(0).getAccount().getId();
-    }
 
     public UUID getBundleId() {
         return billingEvents.get(0).getSubscription().getBundleId();
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
index e2b6965..9a531a7 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
@@ -68,13 +68,15 @@ public class SubscriptionConsumableInArrear {
         }
     };
 
+    private final UUID accountId;
     private final UUID invoiceId;
     private final List<BillingEvent> subscriptionBillingEvents;
     private final LocalDate targetDate;
     private final List<RawUsage> rawSubscriptionUsage;
     private final LocalDate rawUsageStartDate;
 
-    public SubscriptionConsumableInArrear(final UUID invoiceId, final List<BillingEvent> subscriptionBillingEvents, final List<RawUsage> rawUsage, final LocalDate targetDate, final LocalDate rawUsageStartDate) {
+    public SubscriptionConsumableInArrear(final UUID accountId, final UUID invoiceId, final List<BillingEvent> subscriptionBillingEvents, final List<RawUsage> rawUsage, final LocalDate targetDate, final LocalDate rawUsageStartDate) {
+        this.accountId = accountId;
         this.invoiceId = invoiceId;
         this.subscriptionBillingEvents = subscriptionBillingEvents;
         this.targetDate = targetDate;
@@ -136,7 +138,7 @@ public class SubscriptionConsumableInArrear {
                 // Add inflight usage interval if non existent
                 ContiguousIntervalConsumableInArrear existingInterval = inFlightInArrearUsageIntervals.get(usage.getName());
                 if (existingInterval == null) {
-                    existingInterval = new ContiguousIntervalConsumableInArrear(usage, invoiceId, rawSubscriptionUsage, targetDate, rawUsageStartDate);
+                    existingInterval = new ContiguousIntervalConsumableInArrear(usage, accountId, invoiceId, rawSubscriptionUsage, targetDate, rawUsageStartDate);
                     inFlightInArrearUsageIntervals.put(usage.getName(), existingInterval);
                 }
                 // Add billing event for that usage interval
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
index 8667bb3..74d938e 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
@@ -32,6 +32,7 @@ import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.DefaultAccount;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.DefaultPrice;
 import org.killbill.billing.catalog.MockInternationalPrice;
@@ -1082,6 +1083,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         assertEquals(invoices.size(), 2);
     }
 
+
     /*
      *
      * this test verifies that immediate changes give the correct results
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
index 7cd34ee..4b8be24 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
@@ -33,6 +33,7 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.DefaultAccount;
 import org.killbill.billing.catalog.DefaultPrice;
 import org.killbill.billing.catalog.MockInternationalPrice;
 import org.killbill.billing.catalog.MockPlan;
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index 18d1ec7..0ff2d28 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -52,6 +52,7 @@ import org.killbill.billing.entity.EntityPersistenceException;
 import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications;
 import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications.SubscriptionNotification;
 import org.killbill.billing.invoice.api.DryRunArguments;
+import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
@@ -332,11 +333,6 @@ public class TestInvoiceHelper {
         final Account accountOrMockAcount = account != null ? account : mockAccount;
         return new BillingEvent() {
             @Override
-            public Account getAccount() {
-                return accountOrMockAcount;
-            }
-
-            @Override
             public int getBillCycleDayLocal() {
                 return billCycleDayLocal;
             }
@@ -427,6 +423,11 @@ public class TestInvoiceHelper {
         }
 
         @Override
+        public DryRunType getDryRunType() {
+            return DryRunType.TARGET_DATE;
+        }
+
+        @Override
         public PlanPhaseSpecifier getPlanPhaseSpecifier() {
             return null;
         }
@@ -457,7 +458,7 @@ public class TestInvoiceHelper {
         }
 
         @Override
-        public List<PlanPhasePriceOverride> getPlanPhasePriceoverrides() {
+        public List<PlanPhasePriceOverride> getPlanPhasePriceOverrides() {
             return null;
         }
     }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java
index 1e9e609..bff7839 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java
@@ -73,7 +73,7 @@ public class TestSubscriptionConsumableInArrear extends TestUsageInArrearBase {
 
         LocalDate targetDate = new LocalDate(2013, 6, 23);
 
-        final SubscriptionConsumableInArrear foo = new SubscriptionConsumableInArrear(invoiceId, billingEvents, ImmutableList.<RawUsage>of(), targetDate, new LocalDate(dt1, DateTimeZone.UTC));
+        final SubscriptionConsumableInArrear foo = new SubscriptionConsumableInArrear(accountId, invoiceId, billingEvents, ImmutableList.<RawUsage>of(), targetDate, new LocalDate(dt1, DateTimeZone.UTC));
         final List<ContiguousIntervalConsumableInArrear> result = foo.computeInArrearUsageInterval();
         assertEquals(result.size(), 3);
 
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
index 616e852..ac6dfdd 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
@@ -71,7 +71,7 @@ public abstract class TestUsageInArrearBase extends InvoiceTestSuiteNoDB {
     }
 
     protected ContiguousIntervalConsumableInArrear createContiguousIntervalConsumableInArrear(final DefaultUsage usage, List<RawUsage> rawUsages, final LocalDate targetDate, final boolean closedInterval, final BillingEvent... events) {
-        final ContiguousIntervalConsumableInArrear intervalConsumableInArrear = new ContiguousIntervalConsumableInArrear(usage, invoiceId, rawUsages, targetDate, new LocalDate(events[0].getEffectiveDate()));
+        final ContiguousIntervalConsumableInArrear intervalConsumableInArrear = new ContiguousIntervalConsumableInArrear(usage, accountId, invoiceId, rawUsages, targetDate, new LocalDate(events[0].getEffectiveDate()));
         for (BillingEvent event : events) {
             intervalConsumableInArrear.addBillingEvent(event);
         }
@@ -120,7 +120,6 @@ public abstract class TestUsageInArrearBase extends InvoiceTestSuiteNoDB {
 
         final Account account = Mockito.mock(Account.class);
         Mockito.when(account.getId()).thenReturn(accountId);
-        Mockito.when(result.getAccount()).thenReturn(account);
 
         final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
         Mockito.when(subscription.getId()).thenReturn(subscriptionId);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceDryRunJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceDryRunJson.java
index 9bc33ac..bc82ab3 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceDryRunJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceDryRunJson.java
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 
 public class InvoiceDryRunJson {
 
+    private final String dryRunType;
     private final String dryRunAction;
     private final String phaseType;
     private final String productName;
@@ -41,7 +42,8 @@ public class InvoiceDryRunJson {
     private final List<PhasePriceOverrideJson> priceOverrides;
 
     @JsonCreator
-    public InvoiceDryRunJson(@JsonProperty("dryRunAction") @Nullable final String dryRunAction,
+    public InvoiceDryRunJson(@JsonProperty("dryRunType") @Nullable final String dryRunType,
+                             @JsonProperty("dryRunAction") @Nullable final String dryRunAction,
                              @JsonProperty("phaseType") @Nullable final String phaseType,
                              @JsonProperty("productName") @Nullable final String productName,
                              @JsonProperty("productCategory") @Nullable final String productCategory,
@@ -52,6 +54,7 @@ public class InvoiceDryRunJson {
                              @JsonProperty("effectiveDate") @Nullable final LocalDate effectiveDate,
                              @JsonProperty("billingPolicy") @Nullable final String billingPolicy,
                              @JsonProperty("priceOverrides") @Nullable final List<PhasePriceOverrideJson> priceOverrides) {
+        this.dryRunType = dryRunType;
         this.dryRunAction = dryRunAction;
         this.phaseType = phaseType;
         this.productName = productName;
@@ -65,6 +68,10 @@ public class InvoiceDryRunJson {
         this.priceOverrides = priceOverrides;
     }
 
+    public String getDryRunType() {
+        return dryRunType;
+    }
+
     public String getDryRunAction() {
         return dryRunAction;
     }
@@ -129,6 +136,9 @@ public class InvoiceDryRunJson {
         if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
             return false;
         }
+        if (dryRunType != null ? !dryRunType.equals(that.dryRunType) : that.dryRunType != null) {
+            return false;
+        }
         if (dryRunAction != null ? !dryRunAction.equals(that.dryRunAction) : that.dryRunAction != null) {
             return false;
         }
@@ -160,6 +170,7 @@ public class InvoiceDryRunJson {
     @Override
     public int hashCode() {
         int result = dryRunAction != null ? dryRunAction.hashCode() : 0;
+        result = 31 * result + (dryRunType != null ? dryRunType.hashCode() : 0);
         result = 31 * result + (phaseType != null ? phaseType.hashCode() : 0);
         result = 31 * result + (productName != null ? productName.hashCode() : 0);
         result = 31 * result + (productCategory != null ? productCategory.hashCode() : 0);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index 66af04c..241cc16 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -49,12 +49,14 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
+import org.joda.time.DateTimeZone;
 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.AccountData;
 import org.killbill.billing.account.api.AccountEmail;
+import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.account.api.MutableAccountData;
 import org.killbill.billing.catalog.api.Currency;
@@ -152,6 +154,7 @@ public class AccountResource extends JaxRsResourceBase {
                            final AuditUserApi auditUserApi,
                            final CustomFieldUserApi customFieldUserApi,
                            final SubscriptionApi subscriptionApi,
+                           final AccountInternalApi accountInternalApi,
                            final OverdueInternalApi overdueApi,
                            final Clock clock,
                            final PaymentConfig paymentConfig,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index 180a800..7b82b75 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -70,6 +70,7 @@ import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.SubscriptionApiException;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.invoice.api.DryRunArguments;
+import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
@@ -146,7 +147,6 @@ public class InvoiceResource extends JaxRsResourceBase {
         }
     });
 
-
     @Inject
     public InvoiceResource(final AccountUserApi accountUserApi,
                            final InvoiceUserApi invoiceApi,
@@ -315,7 +315,6 @@ public class InvoiceResource extends JaxRsResourceBase {
         }
     }
 
-
     @Timed
     @POST
     @Path("/" + DRY_RUN)
@@ -333,14 +332,14 @@ public class InvoiceResource extends JaxRsResourceBase {
                                           @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
         final LocalDate inputDate;
-        // In the case of subscription dryRun we set the targetDate to be the effective date of the change itself
-        if (dryRunSubscriptionSpec != null && dryRunSubscriptionSpec.getEffectiveDate() != null) {
-            inputDate = dryRunSubscriptionSpec.getEffectiveDate();
-        // In case of Invoice dryRun we also allow the special value UPCOMING_INVOICE_TARGET_DATE where the system will automatically
-        // generate the resulting targetDate for upcoming invoice; in terms of invoice api that maps to passing a null targetDate
-        } else if (targetDate != null && targetDate.equals(UPCOMING_INVOICE_TARGET_DATE)) {
-            inputDate = null;
-        // Finally, in case of Invoice dryRun, we allow a null input date (will default to NOW), or extract the value provided
+        if (dryRunSubscriptionSpec != null) {
+            if (DryRunType.UPCOMING_INVOICE.name().equals(dryRunSubscriptionSpec.getDryRunType())) {
+                inputDate = null;
+            } else if (DryRunType.SUBSCRIPTION_ACTION.name().equals(dryRunSubscriptionSpec.getDryRunType()) && dryRunSubscriptionSpec.getEffectiveDate() != null) {
+                inputDate = dryRunSubscriptionSpec.getEffectiveDate();
+            } else {
+                inputDate = toLocalDate(UUID.fromString(accountId), targetDate, callContext);
+            }
         } else {
             inputDate = toLocalDate(UUID.fromString(accountId), targetDate, callContext);
         }
@@ -540,7 +539,6 @@ public class InvoiceResource extends JaxRsResourceBase {
         }
     }
 
-
     @Timed
     @GET
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + PAYMENTS)
@@ -944,6 +942,7 @@ public class InvoiceResource extends JaxRsResourceBase {
 
     private static class DefaultDryRunArguments implements DryRunArguments {
 
+        private final DryRunType dryRunType;
         private final SubscriptionEventType action;
         private final UUID subscriptionId;
         private final DateTime effectiveDate;
@@ -954,6 +953,7 @@ public class InvoiceResource extends JaxRsResourceBase {
 
         public DefaultDryRunArguments(final InvoiceDryRunJson input, final DateTimeZone accountTimeZone, final Currency currency, final Clock clock) {
             if (input == null) {
+                this.dryRunType = DryRunType.TARGET_DATE;
                 this.action = null;
                 this.subscriptionId = null;
                 this.effectiveDate = null;
@@ -962,37 +962,43 @@ public class InvoiceResource extends JaxRsResourceBase {
                 this.billingPolicy = null;
                 this.overrides = null;
             } else {
+                this.dryRunType = input.getDryRunType() != null ? DryRunType.valueOf(input.getDryRunType()) : DryRunType.TARGET_DATE;
                 this.action = input.getDryRunAction() != null ? SubscriptionEventType.valueOf(input.getDryRunAction()) : null;
                 this.subscriptionId = input.getSubscriptionId() != null ? UUID.fromString(input.getSubscriptionId()) : null;
                 this.bundleId = input.getBundleId() != null ? UUID.fromString(input.getBundleId()) : null;
                 this.effectiveDate = input.getEffectiveDate() != null ? ClockUtil.computeDateTimeWithUTCReferenceTime(input.getEffectiveDate(), clock.getUTCNow().toLocalTime(), accountTimeZone, clock) : null;
                 this.billingPolicy = input.getBillingPolicy() != null ? BillingActionPolicy.valueOf(input.getBillingPolicy()) : null;
-                final PlanPhaseSpecifier planPhaseSpecifier  = (input.getProductName() != null &&
-                                     input.getProductCategory() != null &&
-                                     input.getBillingPeriod() != null) ?
-                                    new PlanPhaseSpecifier(input.getProductName(),
-                                                           ProductCategory.valueOf(input.getProductCategory()),
-                                                           BillingPeriod.valueOf(input.getBillingPeriod()),
-                                                           input.getPriceListName(),
-                                                           input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null) :
-                                    null;
+                final PlanPhaseSpecifier planPhaseSpecifier = (input.getProductName() != null &&
+                                                               input.getProductCategory() != null &&
+                                                               input.getBillingPeriod() != null) ?
+                                                              new PlanPhaseSpecifier(input.getProductName(),
+                                                                                     ProductCategory.valueOf(input.getProductCategory()),
+                                                                                     BillingPeriod.valueOf(input.getBillingPeriod()),
+                                                                                     input.getPriceListName(),
+                                                                                     input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null) :
+                                                              null;
                 this.specifier = planPhaseSpecifier;
                 this.overrides = input.getPriceOverrides() != null ?
                                  ImmutableList.copyOf(Iterables.transform(input.getPriceOverrides(), new Function<PhasePriceOverrideJson, PlanPhasePriceOverride>() {
-                    @Nullable
-                    @Override
-                    public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
-                        if (input.getPhaseName() != null) {
-                            return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
-                        } else {
-                            return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
-                        }
-                    }
-                })) : ImmutableList.<PlanPhasePriceOverride>of();
+                                     @Nullable
+                                     @Override
+                                     public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
+                                         if (input.getPhaseName() != null) {
+                                             return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
+                                         } else {
+                                             return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
+                                         }
+                                     }
+                                 })) : ImmutableList.<PlanPhasePriceOverride>of();
             }
         }
 
         @Override
+        public DryRunType getDryRunType() {
+            return dryRunType;
+        }
+
+        @Override
         public PlanPhaseSpecifier getPlanPhaseSpecifier() {
             return specifier;
         }
@@ -1023,7 +1029,7 @@ public class InvoiceResource extends JaxRsResourceBase {
         }
 
         @Override
-        public List<PlanPhasePriceOverride> getPlanPhasePriceoverrides() {
+        public List<PlanPhasePriceOverride> getPlanPhasePriceOverrides() {
             return overrides;
         }
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 7a97f65..0735138 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -227,8 +227,6 @@ public interface JaxrsResource {
     public static final String INVOICE_TRANSLATION = "translation";
     public static final String INVOICE_CATALOG_TRANSLATION = "catalogTranslation";
 
-    public static final String UPCOMING_INVOICE_TARGET_DATE = "upcomingInvoiceTargetDate";
-
     public static final String COMBO = "combo";
 
 }
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index 24923f7..df27149 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -21,14 +21,12 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
-import org.killbill.billing.catalog.api.BillingPeriod;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.killbill.billing.ErrorCode;
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.BillingAlignment;
+import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
@@ -37,13 +35,13 @@ import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
 import org.killbill.billing.catalog.api.Product;
-import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
-import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
-import org.killbill.billing.subscription.api.SubscriptionBase;
-import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
-import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
+import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
+import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.inject.Inject;
@@ -61,7 +59,7 @@ public class BillCycleDayCalculator {
         this.subscriptionApi = subscriptionApi;
     }
 
-    protected int calculateBcd(final UUID bundleId, final SubscriptionBase subscription, final EffectiveSubscriptionInternalEvent transition, final Account account, final InternalCallContext context)
+    protected int calculateBcd(final ImmutableAccountData account, final int accountBillCycleDayLocal, final UUID bundleId, final SubscriptionBase subscription, final EffectiveSubscriptionInternalEvent transition, final InternalCallContext context)
             throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
 
         final Catalog catalog = catalogService.getFullCatalog(context);
@@ -86,19 +84,16 @@ public class BillCycleDayCalculator {
                                        phase.getPhaseType()),
                 transition.getRequestedTransitionTime());
 
-        return calculateBcdForAlignment(alignment, bundleId, subscription, account, catalog, plan, context);
+        return calculateBcdForAlignment(account, accountBillCycleDayLocal, subscription, alignment, bundleId, catalog, plan, context);
     }
 
     @VisibleForTesting
-    int calculateBcdForAlignment(final BillingAlignment alignment, final UUID bundleId, final SubscriptionBase subscription,
-                                 final Account account, final Catalog catalog, final Plan plan, final InternalCallContext context) throws AccountApiException, SubscriptionBaseApiException, CatalogApiException {
+    int calculateBcdForAlignment(final ImmutableAccountData account, final int accountBillCycleDayLocal, final SubscriptionBase subscription, final BillingAlignment alignment, final UUID bundleId,
+                                 final Catalog catalog, final Plan plan, final InternalCallContext context) throws AccountApiException, SubscriptionBaseApiException, CatalogApiException {
         int result = 0;
         switch (alignment) {
             case ACCOUNT:
-                result = account.getBillCycleDayLocal();
-                if (result == 0) {
-                    result = calculateBcdFromSubscription(subscription, plan, account, catalog, context);
-                }
+                result = accountBillCycleDayLocal != 0 ? accountBillCycleDayLocal : calculateBcdFromSubscription(subscription, plan, account, catalog, context);
                 break;
             case BUNDLE:
                 final SubscriptionBase baseSub = subscriptionApi.getBaseSubscription(bundleId, context);
@@ -122,7 +117,7 @@ public class BillCycleDayCalculator {
     }
 
     @VisibleForTesting
-    int calculateBcdFromSubscription(final SubscriptionBase subscription, final Plan plan, final Account account, final Catalog catalog, final InternalCallContext context)
+    int calculateBcdFromSubscription(final SubscriptionBase subscription, final Plan plan, final ImmutableAccountData account, final Catalog catalog, final InternalCallContext context)
             throws AccountApiException, CatalogApiException {
         // Retrieve the initial phase type for that subscription
         // TODO - this should be extracted somewhere, along with this code above
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
index a55956e..c6ee181 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -89,8 +89,6 @@ public class BlockingCalculator {
             return;
         }
 
-        final Account account = billingEvents.first().getAccount();
-
         final Hashtable<UUID, List<SubscriptionBase>> bundleMap = createBundleSubscriptionMap(billingEvents);
 
         final SortedSet<BillingEvent> billingEventsToAdd = new TreeSet<BillingEvent>();
@@ -100,7 +98,7 @@ public class BlockingCalculator {
         final List<DisabledDuration> blockingDurations = createBlockingDurations(blockingEvents);
         for (final UUID bundleId : bundleMap.keySet()) {
             for (final SubscriptionBase subscription : bundleMap.get(bundleId)) {
-                billingEventsToAdd.addAll(createNewEvents(blockingDurations, billingEvents, account, subscription));
+                billingEventsToAdd.addAll(createNewEvents(blockingDurations, billingEvents, subscription));
                 billingEventsToRemove.addAll(eventsToRemove(blockingDurations, billingEvents, subscription));
             }
         }
@@ -133,7 +131,7 @@ public class BlockingCalculator {
         return result;
     }
 
-    protected SortedSet<BillingEvent> createNewEvents(final List<DisabledDuration> disabledDuration, final SortedSet<BillingEvent> billingEvents, final Account account, final SubscriptionBase subscription) {
+    protected SortedSet<BillingEvent> createNewEvents(final List<DisabledDuration> disabledDuration, final SortedSet<BillingEvent> billingEvents, final SubscriptionBase subscription) {
         final SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
         for (final DisabledDuration duration : disabledDuration) {
             // The first one before the blocked duration
@@ -188,7 +186,6 @@ public class BlockingCalculator {
     }
 
     protected BillingEvent createNewDisableEvent(final DateTime odEventTime, final BillingEvent previousEvent) {
-        final Account account = previousEvent.getAccount();
         final int billCycleDay = previousEvent.getBillCycleDayLocal();
         final SubscriptionBase subscription = previousEvent.getSubscription();
         final DateTime effectiveDate = odEventTime;
@@ -207,7 +204,7 @@ public class BlockingCalculator {
         final Long totalOrdering = globaltotalOrder.getAndIncrement();
         final DateTimeZone tz = previousEvent.getTimeZone();
 
-        return new DefaultBillingEvent(account, subscription, effectiveDate, true, plan, planPhase,
+        return new DefaultBillingEvent(subscription, effectiveDate, true, plan, planPhase,
                                        fixedPrice, recurringPrice, currency,
                                        billingPeriod, billCycleDay,
                                        description, totalOrdering, type, tz);
@@ -215,7 +212,6 @@ public class BlockingCalculator {
 
     protected BillingEvent createNewReenableEvent(final DateTime odEventTime, final BillingEvent previousEvent) {
         // All fields are populated with the event state from before the blocking period, for invoice to resume invoicing
-        final Account account = previousEvent.getAccount();
         final int billCycleDay = previousEvent.getBillCycleDayLocal();
         final SubscriptionBase subscription = previousEvent.getSubscription();
         final DateTime effectiveDate = odEventTime;
@@ -230,7 +226,7 @@ public class BlockingCalculator {
         final Long totalOrdering = globaltotalOrder.getAndIncrement();
         final DateTimeZone tz = previousEvent.getTimeZone();
 
-        return new DefaultBillingEvent(account, subscription, effectiveDate, true, plan, planPhase,
+        return new DefaultBillingEvent(subscription, effectiveDate, true, plan, planPhase,
                                        fixedPrice, recurringPrice, currency,
                                        billingPeriod, billCycleDay,
                                        description, totalOrdering, type, tz);
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
index 1a7f98d..cbf1076 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
@@ -17,14 +17,13 @@
 package org.killbill.billing.junction.plumbing.billing;
 
 import java.math.BigDecimal;
-import java.util.Collections;
 import java.util.List;
 
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
@@ -42,7 +41,6 @@ import com.google.common.collect.Lists;
 
 public class DefaultBillingEvent implements BillingEvent {
 
-    private final Account account;
     private final int billCycleDayLocal;
     private final SubscriptionBase subscription;
     private final DateTime effectiveDate;
@@ -59,11 +57,10 @@ public class DefaultBillingEvent implements BillingEvent {
 
     private final List<Usage> usages;
 
-    public DefaultBillingEvent(final Account account, final EffectiveSubscriptionInternalEvent transition, final SubscriptionBase subscription, final int billCycleDayLocal, final Currency currency, final Catalog catalog) throws CatalogApiException {
+    public DefaultBillingEvent(final ImmutableAccountData account, final EffectiveSubscriptionInternalEvent transition, final SubscriptionBase subscription, final int billCycleDayLocal, final Currency currency, final Catalog catalog) throws CatalogApiException {
 
         final boolean isActive = transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL;
 
-        this.account = account;
         this.billCycleDayLocal = billCycleDayLocal;
         this.subscription = subscription;
         this.effectiveDate = transition.getEffectiveTransitionTime();
@@ -91,12 +88,11 @@ public class DefaultBillingEvent implements BillingEvent {
         this.usages = initializeUsage(isActive);
     }
 
-    public DefaultBillingEvent(final Account account, final SubscriptionBase subscription, final DateTime effectiveDate, final boolean isActive,
+    public DefaultBillingEvent(final SubscriptionBase subscription, final DateTime effectiveDate, final boolean isActive,
                                final Plan plan, final PlanPhase planPhase,
                                final BigDecimal fixedPrice, final BigDecimal recurringPrice, final Currency currency,
                                final BillingPeriod billingPeriod, final int billCycleDayLocal,
                                final String description, final long totalOrdering, final SubscriptionBaseTransitionType type, final DateTimeZone timeZone) {
-        this.account = account;
         this.subscription = subscription;
         this.effectiveDate = effectiveDate;
         this.plan = plan;
@@ -161,11 +157,6 @@ public class DefaultBillingEvent implements BillingEvent {
     }
 
     @Override
-    public Account getAccount() {
-        return account;
-    }
-
-    @Override
     public int getBillCycleDayLocal() {
         return billCycleDayLocal;
     }
@@ -246,7 +237,6 @@ public class DefaultBillingEvent implements BillingEvent {
         sb.append(", planPhaseName=").append(planPhase.getName());
         sb.append(", subscriptionId=").append(subscription.getId());
         sb.append(", totalOrdering=").append(totalOrdering);
-        sb.append(", accountId=").append(account.getId());
         sb.append('}');
         return sb.toString();
     }
@@ -265,9 +255,6 @@ public class DefaultBillingEvent implements BillingEvent {
         if (billCycleDayLocal != that.billCycleDayLocal) {
             return false;
         }
-        if (account != null ? !account.equals(that.account) : that.account != null) {
-            return false;
-        }
         if (billingPeriod != that.billingPeriod) {
             return false;
         }
@@ -310,8 +297,7 @@ public class DefaultBillingEvent implements BillingEvent {
 
     @Override
     public int hashCode() {
-        int result = account != null ? account.hashCode() : 0;
-        result = 31 * result + billCycleDayLocal;
+        int result = 31 * billCycleDayLocal;
         result = 31 * result + (subscription != null ? subscription.hashCode() : 0);
         result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0);
         result = 31 * result + (planPhase != null ? planPhase.hashCode() : 0);
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index 7eddd1a..3fbf992 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -23,10 +23,10 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.account.api.MutableAccountData;
+import org.killbill.billing.account.api.AccountUserApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
@@ -89,7 +89,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
         result.setRecurringBillingMode(currentCatalog.getRecurringBillingMode());
 
         try {
-            final Account account = accountApi.getAccountById(accountId, context);
+            final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
 
             // Check to see if billing is off for the account
             final List<Tag> accountTags = tagApi.getTags(accountId, ObjectType.ACCOUNT, context);
@@ -123,8 +123,8 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
         }
     }
 
-    private void addBillingEventsForBundles(final List<SubscriptionBaseBundle> bundles, final Account account, final DryRunArguments dryRunArguments, final InternalCallContext context,
-                                            final DefaultBillingEventSet result) throws SubscriptionBaseApiException {
+    private void addBillingEventsForBundles(final List<SubscriptionBaseBundle> bundles, final ImmutableAccountData account, final DryRunArguments dryRunArguments, final InternalCallContext context,
+                                            final DefaultBillingEventSet result) throws SubscriptionBaseApiException, AccountApiException {
 
         final boolean dryRunMode = dryRunArguments != null;
 
@@ -136,14 +136,14 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
             final UUID fakeBundleId = UUIDs.randomUUID();
             final List<SubscriptionBase> subscriptions = subscriptionApi.getSubscriptionsForBundle(fakeBundleId, dryRunArguments, context);
 
-            addBillingEventsForSubscription(subscriptions, fakeBundleId, account, dryRunMode, context, result);
+            addBillingEventsForSubscription(account, subscriptions, fakeBundleId, dryRunMode, context, result);
 
         }
 
         for (final SubscriptionBaseBundle bundle : bundles) {
             final DryRunArguments dryRunArgumentsForBundle = (dryRunArguments != null &&
-                                                             dryRunArguments.getBundleId() != null &&
-                                                             dryRunArguments.getBundleId().equals(bundle.getId())) ?
+                                                              dryRunArguments.getBundleId() != null &&
+                                                              dryRunArguments.getBundleId().equals(bundle.getId())) ?
                                                              dryRunArguments : null;
             final List<SubscriptionBase> subscriptions = subscriptionApi.getSubscriptionsForBundle(bundle.getId(), dryRunArgumentsForBundle, context);
 
@@ -155,18 +155,22 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
                     result.getSubscriptionIdsWithAutoInvoiceOff().add(subscription.getId());
                 }
             } else { // billing is not off
-                addBillingEventsForSubscription(subscriptions, bundle.getId(), account, dryRunMode, context, result);
+                addBillingEventsForSubscription(account, subscriptions, bundle.getId(), dryRunMode, context, result);
             }
         }
     }
 
-    private void addBillingEventsForSubscription(final List<SubscriptionBase> subscriptions, final UUID bundleId, final Account account,
+    private void addBillingEventsForSubscription(final ImmutableAccountData account,
+                                                 final List<SubscriptionBase> subscriptions,
+                                                 final UUID bundleId,
                                                  final boolean dryRunMode,
                                                  final InternalCallContext context,
-                                                 final DefaultBillingEventSet result) {
+                                                 final DefaultBillingEventSet result) throws AccountApiException {
 
         // If dryRun is specified, we don't want to to update the account BCD value, so we initialize the flag updatedAccountBCD to true
         boolean updatedAccountBCD = dryRunMode;
+
+        int currentAccountBCD = accountApi.getBCD(account.getId(), context);
         for (final SubscriptionBase subscription : subscriptions) {
 
             // The subscription did not even start, so there is nothing to do yet, we can skip and avoid some NPE down the line when calculating the BCD
@@ -176,12 +180,10 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
 
             for (final EffectiveSubscriptionInternalEvent transition : subscriptionApi.getBillingTransitions(subscription, context)) {
                 try {
-                    final int bcdLocal = bcdCalculator.calculateBcd(bundleId, subscription, transition, account, context);
+                    final int bcdLocal = bcdCalculator.calculateBcd(account, currentAccountBCD, bundleId, subscription, transition, context);
 
-                    if (account.getBillCycleDayLocal() == 0 && !updatedAccountBCD) {
-                        final MutableAccountData modifiedData = account.toMutableAccountData();
-                        modifiedData.setBillCycleDayLocal(bcdLocal);
-                        accountApi.updateAccount(account.getExternalKey(), modifiedData, context);
+                    if (currentAccountBCD == 0 && !updatedAccountBCD) {
+                        accountApi.updateBCD(account.getExternalKey(), bcdLocal, context);
                         updatedAccountBCD = true;
                     }
 
@@ -190,6 +192,9 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
                 } catch (CatalogApiException e) {
                     log.error("Failing to identify catalog components while creating BillingEvent from transition: " +
                               transition.getId().toString(), e);
+                } catch (AccountApiException e) {
+                    // This is unexpected  (failed to update BCD) but if this happens we don't want to ignore..
+                    throw e;
                 } catch (Exception e) {
                     log.warn("Failed while getting BillingEvent", e);
                 }
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
index 5542ff3..adef503 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
@@ -20,11 +20,11 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.catalog.api.BillingAlignment;
 import org.killbill.billing.catalog.api.Catalog;
@@ -60,10 +60,10 @@ public class TestBillCycleDayCalculator extends JunctionTestSuiteNoDB {
         Mockito.when(catalog.findPlan(Mockito.anyString(), Mockito.<DateTime>any(), Mockito.<DateTime>any())).thenReturn(plan);
         Mockito.when(subscription.getLastActivePlan()).thenReturn(plan);
 
-        final Account account = Mockito.mock(Account.class);
+        final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
         Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
-        final Integer billCycleDayLocal = billCycleDayCalculator.calculateBcdForAlignment(BillingAlignment.BUNDLE, bundle.getId(), subscription,
-                                                                                          account, catalog, null, internalCallContext);
+        final Integer billCycleDayLocal = billCycleDayCalculator.calculateBcdForAlignment(account, 0, subscription, BillingAlignment.BUNDLE, bundle.getId(),
+                                                                                          catalog, null, internalCallContext);
 
         Assert.assertEquals(billCycleDayLocal, (Integer) expectedBCDUTC);
     }
@@ -132,7 +132,7 @@ public class TestBillCycleDayCalculator extends JunctionTestSuiteNoDB {
         final Plan plan = Mockito.mock(Plan.class);
         Mockito.when(plan.dateOfFirstRecurringNonZeroCharge(startDateUTC, null)).thenReturn(startDateUTC);
 
-        final Account account = Mockito.mock(Account.class);
+        final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
         Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
 
         final Integer bcd = billCycleDayCalculator.calculateBcdFromSubscription(subscription, plan, account, Mockito.mock(Catalog.class), internalCallContext);
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
index 34ab02f..63438b7 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
@@ -265,6 +265,8 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
         Mockito.when(account.getId()).thenReturn(UUID.randomUUID());
         Mockito.when(account.getTimeZone()).thenReturn(DateTimeZone.UTC);
         Mockito.when(accountInternalApi.getAccountById(Mockito.<UUID>any(), Mockito.<InternalTenantContext>any())).thenReturn(account);
+        Mockito.when(accountInternalApi.getImmutableAccountDataById(Mockito.<UUID>any(), Mockito.<InternalTenantContext>any())).thenReturn(account);
+        Mockito.when(accountInternalApi.getBCD(Mockito.<UUID>any(), Mockito.<InternalTenantContext>any())).thenReturn(billCycleDay);
         return account;
     }
 
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
index b2e8ce6..e81a128 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -321,7 +321,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         disabledDuration.add(new DisabledDuration(now, null));
         billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 1);
         assertEquals(results.first().getEffectiveDate(), now);
@@ -343,7 +343,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
         billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 1);
         assertEquals(results.first().getEffectiveDate(), now);
@@ -364,7 +364,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         disabledDuration.add(new DisabledDuration(now, null));
         billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 0);
     }
@@ -380,7 +380,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
         billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
@@ -405,7 +405,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
         billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
@@ -431,7 +431,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
         billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
@@ -455,7 +455,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
         billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 1);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
@@ -474,7 +474,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
         billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 1);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
@@ -493,7 +493,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
         billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
 
-        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, account, subscription1);
+        final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1);
 
         assertEquals(results.size(), 0);
     }
@@ -535,7 +535,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         final Long totalOrdering = 0L;
         final DateTimeZone tz = DateTimeZone.UTC;
 
-        return new DefaultBillingEvent(account, subscription, effectiveDate, true, plan, planPhase,
+        return new DefaultBillingEvent(subscription, effectiveDate, true, plan, planPhase,
                                        fixedPrice, recurringPrice, currency,
                                        billingPeriod, billCycleDay,
                                        description, totalOrdering, type, tz);
@@ -605,7 +605,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
     private class MockBillingEvent extends DefaultBillingEvent {
 
         public MockBillingEvent() {
-            super(account, subscription1, clock.getUTCNow(), true, null, null, BigDecimal.ZERO, BigDecimal.TEN, Currency.USD, BillingPeriod.ANNUAL,
+            super(subscription1, clock.getUTCNow(), true, null, null, BigDecimal.ZERO, BigDecimal.TEN, Currency.USD, BillingPeriod.ANNUAL,
                   4, "", 3L, SubscriptionBaseTransitionType.CREATE, DateTimeZone.UTC);
         }
     }
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
index a6a2125..aa47d70 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
@@ -172,7 +172,7 @@ public class TestDefaultBillingEvent extends JunctionTestSuiteNoDB {
     public void testToString() throws Exception {
         // Simple test to ensure we have an easy to read toString representation
         final BillingEvent event = createEvent(subscription(ID_ZERO), new DateTime("2012-01-01T00:02:04.000Z", DateTimeZone.UTC), SubscriptionBaseTransitionType.CREATE);
-        Assert.assertEquals(event.toString(), "DefaultBillingEvent{type=CREATE, effectiveDate=2012-01-01T00:02:04.000Z, planPhaseName=Test-trial, subscriptionId=00000000-0000-0000-0000-000000000000, totalOrdering=1, accountId=" + event.getAccount().getId().toString() + "}");
+        Assert.assertEquals(event.toString(), "DefaultBillingEvent{type=CREATE, effectiveDate=2012-01-01T00:02:04.000Z, planPhaseName=Test-trial, subscriptionId=00000000-0000-0000-0000-000000000000, totalOrdering=1}");
     }
 
     private BillingEvent createEvent(final SubscriptionBase sub, final DateTime effectiveDate, final SubscriptionBaseTransitionType type) {
@@ -186,7 +186,7 @@ public class TestDefaultBillingEvent extends JunctionTestSuiteNoDB {
         final PlanPhase shotgunMonthly = createMockMonthlyPlanPhase(null, BigDecimal.ZERO, PhaseType.TRIAL);
 
         final Account account = new MockAccountBuilder().build();
-        return new DefaultBillingEvent(account, sub, effectiveDate, true,
+        return new DefaultBillingEvent(sub, effectiveDate, true,
                                        shotgun, shotgunMonthly,
                                        BigDecimal.ZERO, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, billCycleDay,
                                        "Test Event 1", totalOrdering, type, DateTimeZone.UTC);
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java b/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
index b5e0d13..d676cf9 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
@@ -18,7 +18,7 @@ package org.killbill.billing.overdue.api;
 
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.entitlement.api.BlockingStateType;
@@ -62,7 +62,7 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
 
     @SuppressWarnings("unchecked")
     @Override
-    public OverdueState getOverdueStateFor(final Account overdueable, final TenantContext context) throws OverdueException {
+    public OverdueState getOverdueStateFor(final ImmutableAccountData overdueable, final TenantContext context) throws OverdueException {
         try {
             final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
             final String stateName = accessApi.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, internalCallContextFactory.createInternalTenantContext(context)).getStateName();
@@ -75,7 +75,7 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
     }
 
     @Override
-    public BillingState getBillingStateFor(final Account overdueable, final TenantContext context) throws OverdueException {
+    public BillingState getBillingStateFor(final ImmutableAccountData overdueable, final TenantContext context) throws OverdueException {
         log.debug("Billing state of of {} requested", overdueable.getId());
 
         final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
@@ -84,19 +84,19 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
     }
 
     @Override
-    public OverdueState refreshOverdueStateFor(final Account blockable, final CallContext context) throws OverdueException, OverdueApiException {
+    public OverdueState refreshOverdueStateFor(final ImmutableAccountData blockable, final CallContext context) throws OverdueException, OverdueApiException {
         log.info("Refresh of blockable {} ({}) requested", blockable.getId(), blockable.getClass());
         final InternalCallContext internalCallContext = createInternalCallContext(blockable, context);
         final OverdueWrapper wrapper = factory.createOverdueWrapperFor(blockable, internalCallContext);
         return wrapper.refresh(internalCallContext);
     }
 
-    private InternalCallContext createInternalCallContext(final Account blockable, final CallContext context) {
+    private InternalCallContext createInternalCallContext(final ImmutableAccountData blockable, final CallContext context) {
         return internalCallContextFactory.createInternalCallContext(blockable.getId(), ObjectType.ACCOUNT, context);
     }
 
     @Override
-    public void setOverrideBillingStateForAccount(final Account overdueable, final BillingState state, final CallContext context) {
+    public void setOverrideBillingStateForAccount(final ImmutableAccountData overdueable, final BillingState state, final CallContext context) {
         throw new UnsupportedOperationException();
     }
 }
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
index e84cdb6..384686c 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
@@ -34,6 +34,7 @@ import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -120,7 +121,7 @@ public class OverdueStateApplicator {
     }
 
     public void apply(final OverdueStateSet overdueStateSet, final BillingState billingState,
-                      final Account account, final OverdueState previousOverdueState,
+                      final ImmutableAccountData account, final OverdueState previousOverdueState,
                       final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException, OverdueApiException {
         try {
 
@@ -157,7 +158,7 @@ public class OverdueStateApplicator {
 
             cancelSubscriptionsIfRequired(account, nextOverdueState, context);
 
-            sendEmailIfRequired(billingState, account, nextOverdueState, context);
+            sendEmailIfRequired(account.getId(), billingState, nextOverdueState, context);
 
             avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(account, previousOverdueState, nextOverdueState, context);
 
@@ -169,6 +170,8 @@ public class OverdueStateApplicator {
             if (e.getCode() != ErrorCode.OVERDUE_NO_REEVALUATION_INTERVAL.getCode()) {
                 throw new OverdueException(e);
             }
+        } catch (AccountApiException e) {
+            throw new OverdueException(e);
         }
         try {
             bus.post(createOverdueEvent(account, previousOverdueState.getName(), nextOverdueState.getName(), isBlockBillingTransition(previousOverdueState, nextOverdueState),
@@ -178,7 +181,7 @@ public class OverdueStateApplicator {
         }
     }
 
-    private void avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(final Account account, final OverdueState previousOverdueState,
+    private void avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(final ImmutableAccountData account, final OverdueState previousOverdueState,
                                                                  final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueApiException {
         if (isBlockBillingTransition(previousOverdueState, nextOverdueState)) {
             set_AUTO_INVOICE_OFF_on_blockedBilling(account.getId(), context);
@@ -187,7 +190,7 @@ public class OverdueStateApplicator {
         }
     }
 
-    public void clear(final Account account, final OverdueState previousOverdueState, final OverdueState clearState, final InternalCallContext context) throws OverdueException {
+    public void clear(final ImmutableAccountData account, final OverdueState previousOverdueState, final OverdueState clearState, final InternalCallContext context) throws OverdueException {
 
         log.debug("OverdueStateApplicator:clear : time = " + clock.getUTCNow() + ", previousState = " + previousOverdueState.getName());
 
@@ -209,13 +212,13 @@ public class OverdueStateApplicator {
         }
     }
 
-    private OverdueChangeInternalEvent createOverdueEvent(final Account overdueable, final String previousOverdueStateName, final String nextOverdueStateName,
+    private OverdueChangeInternalEvent createOverdueEvent(final ImmutableAccountData overdueable, final String previousOverdueStateName, final String nextOverdueStateName,
                                                           final boolean isBlockedBilling, final boolean isUnblockedBilling, final InternalCallContext context) throws BlockingApiException {
         return new DefaultOverdueChangeEvent(overdueable.getId(), previousOverdueStateName, nextOverdueStateName, isBlockedBilling, isUnblockedBilling,
                                              context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
     }
 
-    protected void storeNewState(final Account blockable, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
+    protected void storeNewState(final ImmutableAccountData blockable, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
         try {
             blockingApi.setBlockingState(new DefaultBlockingState(blockable.getId(),
                                                                   BlockingStateType.ACCOUNT,
@@ -269,17 +272,17 @@ public class OverdueStateApplicator {
         return nextOverdueState.isDisableEntitlementAndChangesBlocked();
     }
 
-    protected void createFutureNotification(final Account account, final DateTime timeOfNextCheck, final InternalCallContext context) {
+    protected void createFutureNotification(final ImmutableAccountData account, final DateTime timeOfNextCheck, final InternalCallContext context) {
         final OverdueCheckNotificationKey notificationKey = new OverdueCheckNotificationKey(account.getId());
         checkPoster.insertOverdueNotification(account.getId(), timeOfNextCheck, OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, notificationKey, context);
     }
 
-    protected void clearFutureNotification(final Account account, final InternalCallContext context) {
+    protected void clearFutureNotification(final ImmutableAccountData account, final InternalCallContext context) {
         // Need to clear the override table here too (when we add it)
         checkPoster.clearOverdueCheckNotifications(account.getId(), OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, OverdueCheckNotificationKey.class, context);
     }
 
-    private void cancelSubscriptionsIfRequired(final Account account, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
+    private void cancelSubscriptionsIfRequired(final ImmutableAccountData account, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
         if (nextOverdueState.getOverdueCancellationPolicy() == OverdueCancellationPolicy.NONE) {
             return;
         }
@@ -315,7 +318,7 @@ public class OverdueStateApplicator {
         }
     }
 
-    private void computeEntitlementsToCancel(final Account account, final List<Entitlement> result, final CallContext context) throws EntitlementApiException {
+    private void computeEntitlementsToCancel(final ImmutableAccountData account, final List<Entitlement> result, final CallContext context) throws EntitlementApiException {
         final List<Entitlement> allEntitlementsForAccountId = entitlementApi.getAllEntitlementsForAccountId(account.getId(), context);
         // Entitlement is smart enough and will cancel the associated add-ons. See also discussion in https://github.com/killbill/killbill/issues/94
         final Collection<Entitlement> allEntitlementsButAddonsForAccountId = Collections2.<Entitlement>filter(allEntitlementsForAccountId,
@@ -329,8 +332,8 @@ public class OverdueStateApplicator {
         result.addAll(allEntitlementsButAddonsForAccountId);
     }
 
-    private void sendEmailIfRequired(final BillingState billingState, final Account account,
-                                     final OverdueState nextOverdueState, final InternalTenantContext context) {
+    private void sendEmailIfRequired(final UUID accountId, final BillingState billingState,
+                                     final OverdueState nextOverdueState, final InternalTenantContext context) throws AccountApiException {
         // Note: we don't want to fail the full refresh call because sending the email failed.
         // That's the reason why we catch all exceptions here.
         // The alternative would be to: throw new OverdueApiException(e, ErrorCode.EMAIL_SENDING_FAILED);
@@ -340,6 +343,7 @@ public class OverdueStateApplicator {
             return;
         }
 
+        final Account account = accountApi.getAccountById(accountId, context);
         if (Strings.emptyToNull(account.getEmail()) == null) {
             log.warn("Unable to send overdue notification email for account {} and overdueable {}: no email specified", account.getId(), account.getId());
             return;
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/calculator/BillingStateCalculator.java b/overdue/src/main/java/org/killbill/billing/overdue/calculator/BillingStateCalculator.java
index 734264b..7d594fc 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/calculator/BillingStateCalculator.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/calculator/BillingStateCalculator.java
@@ -26,16 +26,15 @@ import java.util.UUID;
 
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
-
-import org.killbill.billing.account.api.Account;
-import org.killbill.billing.payment.api.PaymentResponse;
-import org.killbill.clock.Clock;
+import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.invoice.api.Invoice;
+import org.killbill.billing.invoice.api.InvoiceInternalApi;
 import org.killbill.billing.overdue.config.api.BillingState;
 import org.killbill.billing.overdue.config.api.OverdueException;
-import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.invoice.api.InvoiceInternalApi;
+import org.killbill.billing.payment.api.PaymentResponse;
 import org.killbill.billing.util.tag.Tag;
+import org.killbill.clock.Clock;
 
 import com.google.inject.Inject;
 
@@ -63,7 +62,7 @@ public class BillingStateCalculator {
         this.clock = clock;
     }
 
-    public BillingState calculateBillingState(final Account account, final InternalTenantContext context) throws OverdueException {
+    public BillingState calculateBillingState(final ImmutableAccountData account, final InternalTenantContext context) throws OverdueException {
         final SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForAccount(account.getId(), account.getTimeZone(), context);
 
         final int numberOfUnpaidInvoices = unpaidInvoices.size();
@@ -78,7 +77,6 @@ public class BillingStateCalculator {
         final PaymentResponse responseForLastFailedPayment = PaymentResponse.INSUFFICIENT_FUNDS; //TODO MDW
         final Tag[] tags = new Tag[]{}; //TODO MDW
 
-
         return new BillingState(account.getId(), numberOfUnpaidInvoices, unpaidInvoiceBalance, dateOfEarliestUnpaidInvoice, account.getTimeZone(), idOfEarliestUnpaidInvoice, responseForLastFailedPayment, tags);
     }
 
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
index 1439ae5..0b45601 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
@@ -16,7 +16,7 @@
 
 package org.killbill.billing.overdue.wrapper;
 
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.entitlement.api.BlockingStateType;
@@ -33,14 +33,15 @@ import org.killbill.clock.Clock;
 
 public class OverdueWrapper {
 
-    private final Account overdueable;
+    private final ImmutableAccountData overdueable;
     private final BlockingInternalApi api;
     private final Clock clock;
     private final OverdueStateSet overdueStateSet;
     private final BillingStateCalculator billingStateCalcuator;
     private final OverdueStateApplicator overdueStateApplicator;
 
-    public OverdueWrapper(final Account overdueable, final BlockingInternalApi api,
+    public OverdueWrapper(final ImmutableAccountData overdueable,
+                          final BlockingInternalApi api,
                           final OverdueStateSet overdueStateSet,
                           final Clock clock,
                           final BillingStateCalculator billingStateCalcuator,
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapperFactory.java b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapperFactory.java
index c224c83..9c51f85 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapperFactory.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapperFactory.java
@@ -19,12 +19,11 @@ package org.killbill.billing.overdue.wrapper;
 import java.util.UUID;
 
 import org.joda.time.Period;
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.junction.BlockingInternalApi;
-import org.killbill.billing.overdue.OverdueService;
 import org.killbill.billing.overdue.api.OverdueApiException;
 import org.killbill.billing.overdue.api.OverdueConfig;
 import org.killbill.billing.overdue.applicator.OverdueStateApplicator;
@@ -65,8 +64,9 @@ public class OverdueWrapperFactory {
         this.clock = clock;
         this.overdueConfigCache = overdueConfigCache;
     }
+
     @SuppressWarnings("unchecked")
-    public OverdueWrapper createOverdueWrapperFor(final Account blockable, final InternalTenantContext context) throws OverdueException {
+    public OverdueWrapper createOverdueWrapperFor(final ImmutableAccountData blockable, final InternalTenantContext context) throws OverdueException {
         return (OverdueWrapper) new OverdueWrapper(blockable, api, getOverdueStateSet(context),
                                                    clock, billingStateCalculator, overdueStateApplicator);
     }
@@ -75,7 +75,7 @@ public class OverdueWrapperFactory {
     public OverdueWrapper createOverdueWrapperFor(final UUID id, final InternalTenantContext context) throws OverdueException {
 
         try {
-            final Account account = accountApi.getAccountById(id, context);
+            final ImmutableAccountData account = accountApi.getImmutableAccountDataById(id, context);
             return new OverdueWrapper(account, api, getOverdueStateSet(context),
                                       clock, billingStateCalculator, overdueStateApplicator);
         } catch (AccountApiException e) {
@@ -83,7 +83,6 @@ public class OverdueWrapperFactory {
         }
     }
 
-
     private OverdueStateSet getOverdueStateSet(final InternalTenantContext context) throws OverdueException {
         final OverdueConfig overdueConfig;
         try {
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java b/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
index ac23e0a..5c77f5c 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
@@ -22,13 +22,13 @@ import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.Callable;
 
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.overdue.api.OverdueState;
 import org.killbill.billing.overdue.config.DefaultOverdueConfig;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.overdue.OverdueTestSuiteWithEmbeddedDB;
 import org.killbill.billing.overdue.config.api.OverdueStateSet;
 import org.killbill.xmlloader.XMLLoader;
@@ -45,7 +45,7 @@ public class TestOverdueStateApplicator extends OverdueTestSuiteWithEmbeddedDB {
         final InputStream is = new ByteArrayInputStream(testOverdueHelper.getConfigXml().getBytes());
         final DefaultOverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class);
 
-        final Account account = Mockito.mock(Account.class);
+        final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
         Mockito.when(account.getId()).thenReturn(UUID.randomUUID());
 
         final OverdueStateSet overdueStateSet = config.getOverdueStatesAccount();
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/calculator/TestBillingStateCalculator.java b/overdue/src/test/java/org/killbill/billing/overdue/calculator/TestBillingStateCalculator.java
index 4667992..d8f7b9d 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/calculator/TestBillingStateCalculator.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/calculator/TestBillingStateCalculator.java
@@ -25,6 +25,7 @@ import java.util.UUID;
 
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
@@ -61,7 +62,7 @@ public class TestBillingStateCalculator extends OverdueTestSuiteNoDB {
 
         return new BillingStateCalculator(invoiceApi, clock) {
             @Override
-            public BillingState calculateBillingState(final Account overdueable,
+            public BillingState calculateBillingState(final ImmutableAccountData overdueable,
                                                       final InternalTenantContext context) {
                 return null;
             }
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/TestOverdueHelper.java b/overdue/src/test/java/org/killbill/billing/overdue/TestOverdueHelper.java
index b8ebdb2..bb01c4d 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/TestOverdueHelper.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/TestOverdueHelper.java
@@ -23,11 +23,11 @@ import java.util.UUID;
 
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.overdue.api.OverdueState;
 import org.mockito.Mockito;
 import org.testng.Assert;
 
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceItem;
@@ -116,13 +116,13 @@ public class TestOverdueHelper {
         Assert.assertEquals(result.isBlockBilling(), state.isDisableEntitlementAndChangesBlocked());
     }
 
-    public Account createAccount(final LocalDate dateOfLastUnPaidInvoice) throws SubscriptionBaseApiException, AccountApiException {
+    public ImmutableAccountData createImmutableAccountData(final LocalDate dateOfLastUnPaidInvoice) throws SubscriptionBaseApiException, AccountApiException {
 
         final UUID accountId = UUID.randomUUID();
-        final Account account = Mockito.mock(Account.class);
+        final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
         Mockito.when(account.getId()).thenReturn(accountId);
         Mockito.when(account.getTimeZone()).thenReturn(DateTimeZone.UTC);
-        Mockito.when(accountInternalApi.getAccountById(Mockito.eq(account.getId()), Mockito.<InternalTenantContext>any())).thenReturn(account);
+        Mockito.when(accountInternalApi.getImmutableAccountDataById(Mockito.eq(account.getId()), Mockito.<InternalTenantContext>any())).thenReturn(account);
 
         final Invoice invoice = Mockito.mock(Invoice.class);
         Mockito.when(invoice.getInvoiceDate()).thenReturn(dateOfLastUnPaidInvoice);
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java b/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
index 927af22..c6e2231 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
@@ -19,7 +19,7 @@ package org.killbill.billing.overdue.wrapper;
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 
-import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.junction.DefaultBlockingState;
 import org.killbill.billing.overdue.OverdueTestSuiteWithEmbeddedDB;
 import org.killbill.billing.overdue.api.OverdueState;
@@ -44,24 +44,24 @@ public class TestOverdueWrapper extends OverdueTestSuiteWithEmbeddedDB {
         final DefaultOverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class);
         ((MockOverdueConfigCache) overdueConfigCache).loadOverwriteDefaultOverdueConfig(config);
 
-        Account account;
+        ImmutableAccountData account;
         OverdueWrapper wrapper;
         OverdueState state;
 
         state = config.getOverdueStatesAccount().findState("OD1");
-        account = testOverdueHelper.createAccount(clock.getUTCToday().minusDays(31));
+        account = testOverdueHelper.createImmutableAccountData(clock.getUTCToday().minusDays(31));
         wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
         wrapper.refresh(internalCallContext);
         testOverdueHelper.checkStateApplied(state);
 
         state = config.getOverdueStatesAccount().findState("OD2");
-        account = testOverdueHelper.createAccount(clock.getUTCToday().minusDays(41));
+        account = testOverdueHelper.createImmutableAccountData(clock.getUTCToday().minusDays(41));
         wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
         wrapper.refresh(internalCallContext);
         testOverdueHelper.checkStateApplied(state);
 
         state = config.getOverdueStatesAccount().findState("OD3");
-        account = testOverdueHelper.createAccount(clock.getUTCToday().minusDays(51));
+        account = testOverdueHelper.createImmutableAccountData(clock.getUTCToday().minusDays(51));
         wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
         wrapper.refresh(internalCallContext);
         testOverdueHelper.checkStateApplied(state);
@@ -70,14 +70,14 @@ public class TestOverdueWrapper extends OverdueTestSuiteWithEmbeddedDB {
     @Test(groups = "slow")
     public void testWrapperNoConfig() throws Exception {
 
-        final Account account;
+        final ImmutableAccountData account;
         final OverdueWrapper wrapper;
         final OverdueState state;
 
         final InputStream is = new ByteArrayInputStream(testOverdueHelper.getConfigXml().getBytes());
         final DefaultOverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class);
         state = config.getOverdueStatesAccount().findState(DefaultBlockingState.CLEAR_STATE_NAME);
-        account = testOverdueHelper.createAccount(clock.getUTCToday().minusDays(31));
+        account = testOverdueHelper.createImmutableAccountData(clock.getUTCToday().minusDays(31));
         wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
         final OverdueState result = wrapper.refresh(internalCallContext);
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
index 2d4a157..4803871 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
@@ -18,16 +18,14 @@
 package org.killbill.billing.payment.core.janitor;
 
 import java.io.IOException;
-import java.util.List;
 
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.DefaultCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.events.PaymentInternalEvent;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
-import org.killbill.billing.payment.core.ProcessorBase;
 import org.killbill.billing.payment.core.sm.PaymentControlStateMachineHelper;
 import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
 import org.killbill.billing.payment.dao.PaymentDao;
@@ -123,7 +121,7 @@ abstract class CompletionTaskBase<T> implements Runnable {
     protected <T> T doJanitorOperationWithAccountLock(final JanitorIterationCallback callback, final InternalTenantContext internalTenantContext) {
         GlobalLock lock = null;
         try {
-            final Account account = accountInternalApi.getAccountByRecordId(internalTenantContext.getAccountRecordId(), internalTenantContext);
+            final ImmutableAccountData account = accountInternalApi.getImmutableAccountDataByRecordId(internalTenantContext.getAccountRecordId(), internalTenantContext);
             lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), account.getExternalKey(), paymentConfig.getMaxGlobalLockRetries());
             return callback.doIteration();
         } catch (AccountApiException e) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java b/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
index 1ea86bd..51788f7 100644
--- a/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
@@ -227,13 +227,13 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
         }
     }
 
-    public void process_AUTO_PAY_OFF_removal(final Account account, final InternalCallContext internalCallContext) {
-        final List<PluginAutoPayOffModelDao> entries = controlDao.getAutoPayOffEntry(account.getId());
+    public void process_AUTO_PAY_OFF_removal(final UUID accountId, final InternalCallContext internalCallContext) {
+        final List<PluginAutoPayOffModelDao> entries = controlDao.getAutoPayOffEntry(accountId);
         for (final PluginAutoPayOffModelDao cur : entries) {
             // TODO In theory we should pass not only PLUGIN_NAME, but also all the plugin list associated which the original call
-            retryServiceScheduler.scheduleRetry(ObjectType.ACCOUNT, account.getId(), cur.getAttemptId(), internalCallContext.getTenantRecordId(), ImmutableList.<String>of(PLUGIN_NAME), clock.getUTCNow());
+            retryServiceScheduler.scheduleRetry(ObjectType.ACCOUNT, accountId, cur.getAttemptId(), internalCallContext.getTenantRecordId(), ImmutableList.<String>of(PLUGIN_NAME), clock.getUTCNow());
         }
-        controlDao.removeAutoPayOffEntry(account.getId());
+        controlDao.removeAutoPayOffEntry(accountId);
     }
 
     private UUID getInvoiceId(final Iterable<PluginProperty> pluginProperties) throws PaymentControlApiException {
diff --git a/payment/src/main/java/org/killbill/billing/payment/invoice/PaymentTagHandler.java b/payment/src/main/java/org/killbill/billing/payment/invoice/PaymentTagHandler.java
index 4113349..6270c21 100644
--- a/payment/src/main/java/org/killbill/billing/payment/invoice/PaymentTagHandler.java
+++ b/payment/src/main/java/org/killbill/billing/payment/invoice/PaymentTagHandler.java
@@ -21,13 +21,11 @@ package org.killbill.billing.payment.invoice;
 import java.util.UUID;
 
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.Account;
-import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.control.plugin.api.PaymentControlPluginApi;
 import org.killbill.billing.events.ControlTagDeletionInternalEvent;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
-import org.killbill.billing.control.plugin.api.PaymentControlPluginApi;
 import org.killbill.billing.util.callcontext.CallOrigin;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.UserType;
@@ -66,14 +64,9 @@ public class PaymentTagHandler {
     }
 
     private void processUnpaid_AUTO_PAY_OFF_payments(final UUID accountId, final Long accountRecordId, final Long tenantRecordId, final UUID userToken) {
-        try {
-            final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId,
-                                                                                                                 "PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
-            final Account account = accountApi.getAccountById(accountId, internalCallContext);
-            ((InvoicePaymentControlPluginApi) invoicePaymentControlPlugin).process_AUTO_PAY_OFF_removal(account, internalCallContext);
+        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId,
+                                                                                                             "PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
+        ((InvoicePaymentControlPluginApi) invoicePaymentControlPlugin).process_AUTO_PAY_OFF_removal(accountId, internalCallContext);
 
-        } catch (final AccountApiException e) {
-            log.warn(String.format("Failed to process process  removal AUTO_PAY_OFF for account %s", accountId), e);
-        }
     }
 }

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 553510e..6f2be43 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.45</version>
+        <version>0.47</version>
     </parent>
     <artifactId>killbill</artifactId>
     <version>0.15.6-SNAPSHOT</version>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
index 0c65c04..4457006 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
@@ -24,8 +24,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
-import javax.annotation.Nullable;
-
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
@@ -40,9 +38,9 @@ import org.killbill.billing.client.model.InvoiceItem;
 import org.killbill.billing.client.model.InvoicePayment;
 import org.killbill.billing.client.model.InvoicePayments;
 import org.killbill.billing.client.model.Invoices;
-import org.killbill.billing.client.model.Payment;
 import org.killbill.billing.client.model.PaymentMethod;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
+import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.payment.provider.ExternalPaymentProviderPlugin;
 import org.killbill.billing.util.api.AuditLevel;
 import org.testng.Assert;
@@ -52,7 +50,6 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
@@ -95,7 +92,10 @@ public class TestInvoice extends TestJaxrsBase {
         assertEquals(firstInvoiceByNumberJson, invoiceJson);
 
         // Then create a dryRun for next upcoming invoice
-        final Invoice dryRunInvoice = killBillClient.createDryRunInvoice(accountJson.getAccountId(), null, true, null, createdBy, reason, comment);
+        final InvoiceDryRun dryRunArg = new InvoiceDryRun(DryRunType.UPCOMING_INVOICE, null,
+                                                          null, null, null, null, null, null, null, null, null, null);
+
+        final Invoice dryRunInvoice = killBillClient.createDryRunInvoice(accountJson.getAccountId(), null, dryRunArg, createdBy, reason, comment);
         assertEquals(dryRunInvoice.getBalance(), new BigDecimal("249.95"));
         assertEquals(dryRunInvoice.getTargetDate(), new LocalDate(2012, 6, 25));
         assertEquals(dryRunInvoice.getItems().size(), 1);
@@ -112,7 +112,6 @@ public class TestInvoice extends TestJaxrsBase {
         assertEquals(newInvoiceList.size(), 3);
     }
 
-
     @Test(groups = "slow", description = "Can create a subscription in dryRun mode and get an invoice back")
     public void testDryRunSubscriptionCreate() throws Exception {
         final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
@@ -120,9 +119,9 @@ public class TestInvoice extends TestJaxrsBase {
 
         // "Assault-Rifle", BillingPeriod.ANNUAL, "rescue", BillingActionPolicy.IMMEDIATE,
         final Account accountJson = createAccountWithDefaultPaymentMethod();
-        final InvoiceDryRun dryRunArg = new InvoiceDryRun(SubscriptionEventType.START_BILLING,
+        final InvoiceDryRun dryRunArg = new InvoiceDryRun(DryRunType.TARGET_DATE, SubscriptionEventType.START_BILLING,
                                                           null, "Assault-Rifle", ProductCategory.BASE, BillingPeriod.ANNUAL, null, null, null, null, null, null);
-        final Invoice dryRunInvoice = killBillClient.createDryRunInvoice(accountJson.getAccountId(), new LocalDate(initialDate, DateTimeZone.forID(accountJson.getTimeZone())), false, dryRunArg, createdBy, reason, comment);
+        final Invoice dryRunInvoice = killBillClient.createDryRunInvoice(accountJson.getAccountId(), new LocalDate(initialDate, DateTimeZone.forID(accountJson.getTimeZone())), dryRunArg, createdBy, reason, comment);
         assertEquals(dryRunInvoice.getItems().size(), 1);
 
     }
@@ -352,7 +351,6 @@ public class TestInvoice extends TestJaxrsBase {
         assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId()).size(), 3);
     }
 
-
     @Test(groups = "slow", description = "Can create multiple external charges")
     public void testExternalCharges() throws Exception {
         final Account accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
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;
     }
 }
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();
     }