killbill-aplcache

account: update AccountDao to follow the new conventions *

11/9/2012 5:27:07 PM

Details

diff --git a/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java b/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
index 7a84076..d75cc23 100644
--- a/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
@@ -31,7 +31,6 @@ import com.ning.billing.account.dao.AccountDao;
 import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
 
 public class DefaultAccountInternalApi implements AccountInternalApi {
@@ -46,8 +45,7 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
     }
 
     @Override
-    public Account getAccountById(final UUID accountId, final InternalTenantContext context)
-            throws AccountApiException {
+    public Account getAccountById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
         final Account account = accountDao.getById(accountId, context);
         if (account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
@@ -56,21 +54,16 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
     }
 
     @Override
-    public Account getAccountByRecordId(final Long recordId,
-                                        final InternalTenantContext context) throws AccountApiException {
+    public Account getAccountByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
         return accountDao.getByRecordId(recordId, context);
     }
 
     @Override
     public void updateAccount(final String externalKey, final AccountData accountData,
                               final InternalCallContext context) throws AccountApiException {
-        try {
-            final Account account = getAccountByKey(externalKey, context);
-            final Account updatedAccount = new DefaultAccount(account.getId(), accountData);
-            accountDao.update(updatedAccount, context);
-        } catch (EntityPersistenceException e) {
-            throw new AccountApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID);
-        }
+        final Account account = getAccountByKey(externalKey, context);
+        final Account updatedAccount = new DefaultAccount(account.getId(), accountData);
+        accountDao.update(updatedAccount, context);
     }
 
     @Override
@@ -80,8 +73,7 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
     }
 
     @Override
-    public Account getAccountByKey(final String key, final InternalTenantContext context)
-            throws AccountApiException {
+    public Account getAccountByKey(final String key, final InternalTenantContext context) throws AccountApiException {
         final Account account = accountDao.getAccountByKey(key, context);
         if (account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
@@ -90,18 +82,13 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
     }
 
     @Override
-    public void removePaymentMethod(final UUID accountId, final InternalCallContext context)
-            throws AccountApiException {
+    public void removePaymentMethod(final UUID accountId, final InternalCallContext context) throws AccountApiException {
         updatePaymentMethod(accountId, null, context);
     }
 
     @Override
     public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId,
                                     final InternalCallContext context) throws AccountApiException {
-        try {
-            accountDao.updatePaymentMethod(accountId, paymentMethodId, context);
-        } catch (final EntityPersistenceException e) {
-            throw new AccountApiException(e, e.getCode(), e.getMessage());
-        }
+        accountDao.updatePaymentMethod(accountId, paymentMethodId, context);
     }
 }
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
index 9869b97..5986385 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
@@ -36,7 +36,6 @@ import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.TenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
 
 import com.google.inject.Inject;
 
@@ -58,14 +57,14 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public Account createAccount(final AccountData data, final CallContext context) throws AccountApiException {
-        final Account account = new DefaultAccount(data);
-
-        try {
-            accountDao.create(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
-        } catch (AccountApiException e) {
-            throw new AccountApiException(e, ErrorCode.ACCOUNT_CREATION_FAILED);
+        // Not transactional, but there is a db constraint on that column
+        if (getIdFromKey(data.getExternalKey(), context) != null) {
+            throw new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, data.getExternalKey());
         }
 
+        final Account account = new DefaultAccount(data);
+        accountDao.create(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
+
         return account;
     }
 
@@ -75,6 +74,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
         if (account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
         }
+
         return account;
     }
 
@@ -84,6 +84,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
         if (account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, id);
         }
+
         return account;
     }
 
@@ -99,25 +100,13 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public void updateAccount(final Account account, final CallContext context) throws AccountApiException {
-        try {
-            accountDao.update(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
-        } catch (EntityPersistenceException e) {
-            throw new AccountApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, account.getId());
-        }
-
+        accountDao.update(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
     }
 
     @Override
-    public void updateAccount(final UUID accountId, final AccountData accountData, final CallContext context)
-            throws AccountApiException {
-        try {
-            final Account account = new DefaultAccount(accountId, accountData);
-            accountDao.update(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
-        } catch (EntityPersistenceException e) {
-            throw new AccountApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID);
-        } catch (RuntimeException e /* EntityPersistenceException */) {
-            throw new AccountApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
-        }
+    public void updateAccount(final UUID accountId, final AccountData accountData, final CallContext context) throws AccountApiException {
+        final Account account = new DefaultAccount(accountId, accountData);
+        updateAccount(account, context);
     }
 
     @Override
@@ -130,20 +119,19 @@ public class DefaultAccountUserApi implements AccountUserApi {
     }
 
     @Override
-    public Account migrateAccount(final MigrationAccountData data, final CallContext context)
-            throws AccountApiException {
+    public Account migrateAccount(final MigrationAccountData data, final CallContext context) throws AccountApiException {
+        // Create a special (migration) context
         final DateTime createdDate = data.getCreatedDate() == null ? context.getCreatedDate() : data.getCreatedDate();
         final DateTime updatedDate = data.getUpdatedDate() == null ? context.getUpdatedDate() : data.getUpdatedDate();
         final CallContext migrationContext = callContextFactory.toMigrationCallContext(context, createdDate, updatedDate);
+
+        // Create the account
         final Account account = new DefaultAccount(data);
+        createAccount(account, migrationContext);
 
-        try {
-            accountDao.create(account, internalCallContextFactory.createInternalCallContext(account.getId(), migrationContext));
-            for (final String cur : data.getAdditionalContactEmails()) {
-                addEmail(account.getId(), new DefaultAccountEmail(account.getId(), cur), migrationContext);
-            }
-        } catch (AccountApiException e) {
-            throw new AccountApiException(e, ErrorCode.ACCOUNT_CREATION_FAILED);
+        // Add associated contact emails
+        for (final String cur : data.getAdditionalContactEmails()) {
+            addEmail(account.getId(), new DefaultAccountEmail(account.getId(), cur), migrationContext);
         }
 
         return account;
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
index 5c5243a..3935b19 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
@@ -22,7 +22,6 @@ import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.entity.dao.EntityDao;
 
 public interface AccountDao extends EntityDao<Account, AccountApiException> {
@@ -38,7 +37,7 @@ public interface AccountDao extends EntityDao<Account, 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 EntityPersistenceException;
+    public void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
 
-    public void update(Account account, InternalCallContext context) throws EntityPersistenceException;
+    public void update(Account account, InternalCallContext context) throws AccountApiException;
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
index 30d38a9..3f4ba79 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
@@ -16,22 +16,24 @@
 
 package com.ning.billing.account.dao;
 
-import java.util.List;
 import java.util.UUID;
 
 import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.BillingExceptionBase;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
+import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.entity.EntityPersistenceException;
+import com.ning.billing.util.entity.dao.EntityDaoBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
@@ -43,100 +45,85 @@ import com.ning.billing.util.svcsapi.bus.InternalBus.EventBusException;
 
 import com.google.inject.Inject;
 
-public class AuditedAccountDao implements AccountDao {
+public class AuditedAccountDao extends EntityDaoBase<Account, AccountApiException> implements AccountDao {
 
     private static final Logger log = LoggerFactory.getLogger(AuditedAccountDao.class);
 
-    private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
-    private final AccountSqlDao accountSqlDao;
     private final InternalBus eventBus;
     private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
     public AuditedAccountDao(final IDBI dbi, final InternalBus eventBus, final InternalCallContextFactory internalCallContextFactory) {
+        super(new EntitySqlDaoTransactionalJdbiWrapper(dbi), AccountSqlDao.class);
         this.eventBus = eventBus;
-        this.accountSqlDao = dbi.onDemand(AccountSqlDao.class);
         this.internalCallContextFactory = internalCallContextFactory;
-        transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi);
     }
 
     @Override
-    public Account getAccountByKey(final String key, final InternalTenantContext context) {
-        return accountSqlDao.getAccountByKey(key, context);
+    protected AccountApiException generateAlreadyExistsException(final Account account, final InternalCallContext context) {
+        return new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, account.getExternalKey());
     }
 
     @Override
-    public UUID getIdFromKey(final String externalKey, final InternalTenantContext context) throws AccountApiException {
-        if (externalKey == null) {
-            throw new AccountApiException(ErrorCode.ACCOUNT_CANNOT_MAP_NULL_KEY, "");
+    protected void postBusEventFromTransaction(final Account account, final Account savedAccount, final ChangeType changeType,
+                                               final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context) throws BillingExceptionBase {
+        // This is only called for the create call (see update below)
+        switch (changeType) {
+            case INSERT:
+                break;
+            default:
+                return;
         }
-        return accountSqlDao.getIdFromKey(externalKey, context);
-    }
 
-    @Override
-    public Account getById(final UUID id, final InternalTenantContext context) {
-        return accountSqlDao.getById(id.toString(), context);
-    }
-
-    @Override
-    public Account getByRecordId(final Long recordId, final InternalTenantContext context) {
-        return accountSqlDao.getByRecordId(recordId, context);
-    }
-
-    @Override
-    public List<Account> get(final InternalTenantContext context) {
-        return accountSqlDao.get(context);
+        final Long recordId = getRecordId(savedAccount.getId(), context);
+        // We need to re-hydrate the context with the account record id
+        final InternalCallContext rehydratedContext = internalCallContextFactory.createInternalCallContext(recordId, context);
+        final AccountCreationInternalEvent creationEvent = new DefaultAccountCreationEvent(savedAccount,
+                                                                                           rehydratedContext.getUserToken(),
+                                                                                           context.getAccountRecordId(),
+                                                                                           context.getTenantRecordId());
+        try {
+            eventBus.postFromTransaction(creationEvent, entitySqlDaoWrapperFactory, rehydratedContext);
+        } catch (final EventBusException e) {
+            log.warn("Failed to post account creation event for account " + savedAccount.getId(), e);
+        }
     }
 
     @Override
-    public Long getRecordId(final UUID id, final InternalTenantContext context) {
-        return accountSqlDao.getRecordId(id.toString(), context);
+    public Account getAccountByKey(final String key, final InternalTenantContext context) {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Account>() {
+            @Override
+            public Account inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getAccountByKey(key, context);
+            }
+        });
     }
 
     @Override
-    public void create(final Account account, final InternalCallContext context) throws AccountApiException {
-        final String key = account.getExternalKey();
+    public UUID getIdFromKey(final String externalKey, final InternalTenantContext context) throws AccountApiException {
+        if (externalKey == null) {
+            throw new AccountApiException(ErrorCode.ACCOUNT_CANNOT_MAP_NULL_KEY, "");
+        }
 
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<UUID>() {
             @Override
-            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws AccountApiException, InternalBus.EventBusException {
-                final AccountSqlDao transactionalDao = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
-
-                final Account currentAccount = transactionalDao.getAccountByKey(key, context);
-                if (currentAccount != null) {
-                    throw new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, key);
-                }
-
-                transactionalDao.create(account, context);
-
-                final Long recordId = accountSqlDao.getRecordId(account.getId().toString(), context);
-                // We need to re-hydrate the context with the account record id
-                final InternalCallContext rehydratedContext = internalCallContextFactory.createInternalCallContext(recordId, context);
-                final AccountCreationInternalEvent creationEvent = new DefaultAccountCreationEvent(account,
-                                                                                                   rehydratedContext.getUserToken(),
-                                                                                                   context.getAccountRecordId(),
-                                                                                                   context.getTenantRecordId());
-                try {
-                    eventBus.postFromTransaction(creationEvent, entitySqlDaoWrapperFactory, rehydratedContext);
-                } catch (final EventBusException e) {
-                    log.warn("Failed to post account creation event for account " + account.getId(), e);
-                }
-                return null;
+            public UUID inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getIdFromKey(externalKey, context);
             }
         });
     }
 
     @Override
-    public void update(final Account specifiedAccount, final InternalCallContext context) {
+    public void update(final Account specifiedAccount, final InternalCallContext context) throws AccountApiException {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
-            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws EntityPersistenceException, InternalBus.EventBusException {
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws InternalBus.EventBusException, AccountApiException {
                 final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
 
                 final UUID accountId = specifiedAccount.getId();
                 final Account currentAccount = transactional.getById(accountId.toString(), context);
                 if (currentAccount == null) {
-                    throw new EntityPersistenceException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
+                    throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
                 }
 
                 // Set unspecified (null) fields to their current values
@@ -163,45 +150,32 @@ public class AuditedAccountDao implements AccountDao {
     }
 
     @Override
-    public void test(final InternalTenantContext context) {
-        accountSqlDao.test(context);
-    }
+    public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws AccountApiException {
+        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+            @Override
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws EntityPersistenceException, InternalBus.EventBusException {
+                final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
 
-    @Override
-    public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws EntityPersistenceException {
-        try {
-            transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
-                @Override
-                public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws EntityPersistenceException, InternalBus.EventBusException {
-                    final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
-
-                    final Account currentAccount = transactional.getById(accountId.toString(), context);
-                    if (currentAccount == null) {
-                        throw new EntityPersistenceException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
-                    }
-                    final String thePaymentMethodId = paymentMethodId != null ? paymentMethodId.toString() : null;
-                    transactional.updatePaymentMethod(accountId.toString(), thePaymentMethodId, context);
-
-                    final Account account = transactional.getById(accountId.toString(), context);
-                    final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId, context.getUserToken(), currentAccount, account,
-                                                                                                 context.getAccountRecordId(), context.getTenantRecordId());
-
-                    if (changeEvent.hasChanges()) {
-                        try {
-                            eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory, context);
-                        } catch (final EventBusException e) {
-                            log.warn("Failed to post account change event for account " + accountId, e);
-                        }
+                final Account currentAccount = transactional.getById(accountId.toString(), context);
+                if (currentAccount == null) {
+                    throw new EntityPersistenceException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
+                }
+                final String thePaymentMethodId = paymentMethodId != null ? paymentMethodId.toString() : null;
+                transactional.updatePaymentMethod(accountId.toString(), thePaymentMethodId, context);
+
+                final Account account = transactional.getById(accountId.toString(), context);
+                final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId, context.getUserToken(), currentAccount, account,
+                                                                                             context.getAccountRecordId(), context.getTenantRecordId());
+
+                if (changeEvent.hasChanges()) {
+                    try {
+                        eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory, context);
+                    } catch (final EventBusException e) {
+                        log.warn("Failed to post account change event for account " + accountId, e);
                     }
-                    return null;
                 }
-            });
-        } catch (final RuntimeException re) {
-            if (re.getCause() instanceof EntityPersistenceException) {
-                throw (EntityPersistenceException) re.getCause();
-            } else {
-                throw re;
+                return null;
             }
-        }
+        });
     }
 }
diff --git a/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
index a3d6075..e50cc57 100644
--- a/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
+++ b/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
@@ -1,5 +1,7 @@
 group AccountDaoSql: EntitySqlDao;
 
+tableName() ::= "accounts";
+historyTableName() ::= "account_history";
 
 tableFields(prefix) ::= <<
   <prefix>external_key
@@ -54,9 +56,9 @@ tableValues() ::= <<
 , :updatedBy
  >>
 
-historyTableName() ::= "account_history"
-
-accountRecordIdField(prefix) ::= ""
+/** The accounts table doesn't have an account_record_id column (it's the record_id) **/
+accountRecordIdFieldWithComma(prefix) ::= ""
+accountRecordIdValueWithComma(prefix) ::= ""
 
 update() ::= <<
     UPDATE accounts
diff --git a/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
index fddfbc1..adab356 100644
--- a/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
@@ -16,28 +16,28 @@
 
 package com.ning.billing.account.dao;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
 
+import com.ning.billing.ErrorCode;
 import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.DefaultAccount;
+import com.ning.billing.account.api.DefaultMutableAccountData;
 import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.entity.EntityPersistenceException;
+import com.ning.billing.util.entity.dao.MockEntityDaoBase;
 import com.ning.billing.util.events.AccountChangeInternalEvent;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.svcsapi.bus.InternalBus.EventBusException;
 
 import com.google.inject.Inject;
 
-public class MockAccountDao implements AccountDao {
+public class MockAccountDao extends MockEntityDaoBase<Account, AccountApiException> implements AccountDao {
 
     private final InternalBus eventBus;
-    private final Map<UUID, Account> accounts = new ConcurrentHashMap<UUID, Account>();
 
     @Inject
     public MockAccountDao(final InternalBus eventBus) {
@@ -45,42 +45,41 @@ public class MockAccountDao implements AccountDao {
     }
 
     @Override
-    public Long getRecordId(final UUID id, final InternalTenantContext context) {
-        return 1L;
-    }
-
-    @Override
-    public void create(final Account account, final InternalCallContext context) {
-        accounts.put(account.getId(), account);
+    public void create(final Account account, final InternalCallContext context) throws AccountApiException {
+        super.create(account, context);
 
         try {
-            eventBus.post(new DefaultAccountCreationEvent(account, null, 1L, 1L), context);
+            eventBus.post(new DefaultAccountCreationEvent(account, null, getRecordId(account.getId(), context), context.getTenantRecordId()), context);
         } catch (final EventBusException ex) {
             throw new RuntimeException(ex);
         }
     }
 
     @Override
-    public Account getById(final UUID id, final InternalTenantContext context) {
-        return accounts.get(id);
-    }
-
-    @Override
-    public List<Account> get(final InternalTenantContext context) {
-        return new ArrayList<Account>(accounts.values());
-    }
+    public void update(final Account account, final InternalCallContext context) {
+        final Account currentAccount = getById(account.getId(), context);
+        super.update(account, context);
 
-    @Override
-    public void test(final InternalTenantContext context) {
+        final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), null, currentAccount, account,
+                                                                                     getRecordId(account.getId(), context), context.getTenantRecordId());
+        if (changeEvent.hasChanges()) {
+            try {
+                eventBus.post(changeEvent, context);
+            } catch (final EventBusException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
     }
 
     @Override
     public Account getAccountByKey(final String externalKey, final InternalTenantContext context) {
-        for (final Account account : accounts.values()) {
-            if (externalKey.equals(account.getExternalKey())) {
+        for (final Map<Long, Account> accountRow : entities.values()) {
+            final Account account = accountRow.values().iterator().next();
+            if (account.getExternalKey().equals(externalKey)) {
                 return account;
             }
         }
+
         return null;
     }
 
@@ -91,25 +90,15 @@ public class MockAccountDao implements AccountDao {
     }
 
     @Override
-    public void update(final Account account, final InternalCallContext context) {
-        final Account currentAccount = accounts.put(account.getId(), account);
-
-        final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), null, currentAccount, account, 1L, 1L);
-        if (changeEvent.hasChanges()) {
-            try {
-                eventBus.post(changeEvent, context);
-            } catch (final EventBusException ex) {
-                throw new RuntimeException(ex);
-            }
+    public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws AccountApiException {
+        final Account currentAccount = getById(accountId, context);
+        if (currentAccount == null) {
+            throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
         }
-    }
 
-    @Override
-    public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws EntityPersistenceException {
-    }
+        final DefaultMutableAccountData updatedAccount = new DefaultMutableAccountData(currentAccount);
+        updatedAccount.setPaymentMethodId(paymentMethodId);
 
-    @Override
-    public Account getByRecordId(final Long recordId, final InternalTenantContext context) {
-        return null;
+        update(new DefaultAccount(updatedAccount), context);
     }
 }