killbill-memoizeit

account: soft delete emails Signed-off-by: Pierre-Alexandre

11/15/2012 7:24:37 PM

Changes

account/src/main/java/com/ning/billing/account/dao/AccountEmailDao.java 33(+0 -33)

account/src/main/java/com/ning/billing/account/dao/DefaultAccountEmailDao.java 69(+0 -69)

account/src/test/java/com/ning/billing/account/dao/MockAccountEmailDao.java 43(+0 -43)

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 e5acd59..ed67f74 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
@@ -29,7 +29,6 @@ import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.api.DefaultAccountEmail;
 import com.ning.billing.account.dao.AccountDao;
-import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.account.dao.AccountEmailModelDao;
 import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.util.callcontext.InternalCallContext;
@@ -43,12 +42,10 @@ import com.google.common.collect.ImmutableList;
 public class DefaultAccountInternalApi implements AccountInternalApi {
 
     private final AccountDao accountDao;
-    private final AccountEmailDao accountEmailDao;
 
     @Inject
-    public DefaultAccountInternalApi(final AccountDao accountDao, final AccountEmailDao accountEmailDao) {
+    public DefaultAccountInternalApi(final AccountDao accountDao) {
         this.accountDao = accountDao;
-        this.accountEmailDao = accountEmailDao;
     }
 
     @Override
@@ -63,10 +60,9 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
     @Override
     public Account getAccountByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
         try {
-        final AccountModelDao account = accountDao.getByRecordId(recordId, context);
-        return new DefaultAccount(account);
+            final AccountModelDao account = accountDao.getByRecordId(recordId, context);
+            return new DefaultAccount(account);
         } catch (NullPointerException e) {
-            e.printStackTrace();;
             return null;
         }
     }
@@ -89,7 +85,7 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
     @Override
     public List<AccountEmail> getEmails(final UUID accountId,
                                         final InternalTenantContext context) {
-        return ImmutableList.<AccountEmail>copyOf(Collections2.transform(accountEmailDao.getByAccountId(accountId, context),
+        return ImmutableList.<AccountEmail>copyOf(Collections2.transform(accountDao.getEmailsByAccountId(accountId, context),
                                                                          new Function<AccountEmailModelDao, AccountEmail>() {
                                                                              @Override
                                                                              public AccountEmail apply(final AccountEmailModelDao input) {
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 05ddb29..a633e09 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
@@ -33,7 +33,6 @@ import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.api.DefaultAccountEmail;
 import com.ning.billing.account.api.MigrationAccountData;
 import com.ning.billing.account.dao.AccountDao;
-import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.account.dao.AccountEmailModelDao;
 import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.util.callcontext.CallContext;
@@ -51,15 +50,13 @@ public class DefaultAccountUserApi implements AccountUserApi {
     private final CallContextFactory callContextFactory;
     private final InternalCallContextFactory internalCallContextFactory;
     private final AccountDao accountDao;
-    private final AccountEmailDao accountEmailDao;
 
     @Inject
     public DefaultAccountUserApi(final CallContextFactory callContextFactory, final InternalCallContextFactory internalCallContextFactory,
-                                 final AccountDao accountDao, final AccountEmailDao accountEmailDao) {
+                                 final AccountDao accountDao) {
         this.callContextFactory = callContextFactory;
         this.internalCallContextFactory = internalCallContextFactory;
         this.accountDao = accountDao;
-        this.accountEmailDao = accountEmailDao;
     }
 
     @Override
@@ -165,7 +162,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public List<AccountEmail> getEmails(final UUID accountId, final TenantContext context) {
-        return ImmutableList.<AccountEmail>copyOf(Collections2.transform(accountEmailDao.getByAccountId(accountId, internalCallContextFactory.createInternalTenantContext(context)),
+        return ImmutableList.<AccountEmail>copyOf(Collections2.transform(accountDao.getEmailsByAccountId(accountId, internalCallContextFactory.createInternalTenantContext(context)),
                                                                          new Function<AccountEmailModelDao, AccountEmail>() {
                                                                              @Override
                                                                              public AccountEmail apply(final AccountEmailModelDao input) {
@@ -176,11 +173,11 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public void addEmail(final UUID accountId, final AccountEmail email, final CallContext context) throws AccountApiException {
-        accountEmailDao.create(new AccountEmailModelDao(email), internalCallContextFactory.createInternalCallContext(accountId, context));
+        accountDao.addEmail(new AccountEmailModelDao(email), internalCallContextFactory.createInternalCallContext(accountId, context));
     }
 
     @Override
     public void removeEmail(final UUID accountId, final AccountEmail email, final CallContext context) {
-        accountEmailDao.delete(new AccountEmailModelDao(email), internalCallContextFactory.createInternalCallContext(accountId, context));
+        accountDao.removeEmail(new AccountEmailModelDao(email, false), internalCallContextFactory.createInternalCallContext(accountId, context));
     }
 }
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 ead462f..8ab5f98 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
@@ -16,6 +16,7 @@
 
 package com.ning.billing.account.dao;
 
+import java.util.List;
 import java.util.UUID;
 
 import com.ning.billing.account.api.Account;
@@ -40,4 +41,10 @@ public interface AccountDao extends EntityDao<AccountModelDao, Account, AccountA
     public void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
 
     public void update(AccountModelDao account, InternalCallContext context) throws AccountApiException;
+
+    public void addEmail(AccountEmailModelDao email, InternalCallContext context) throws AccountApiException;
+
+    public void removeEmail(AccountEmailModelDao email, InternalCallContext context);
+
+    public List<AccountEmailModelDao> getEmailsByAccountId(UUID accountId, InternalTenantContext context);
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailModelDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailModelDao.java
index 8ac1499..375ea7f 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailModelDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailModelDao.java
@@ -18,8 +18,6 @@ package com.ning.billing.account.dao;
 
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-
 import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.EntityBase;
@@ -29,17 +27,19 @@ public class AccountEmailModelDao extends EntityBase implements EntityModelDao<A
 
     private UUID accountId;
     private String email;
+    private Boolean isActive;
 
     public AccountEmailModelDao() { /* For the DAO mapper */ }
 
-    public AccountEmailModelDao(final UUID id, final DateTime createdDate, final DateTime updatedDate, final UUID accountId, final String email) {
-        super(id, createdDate, updatedDate);
-        this.accountId = accountId;
-        this.email = email;
+    public AccountEmailModelDao(final AccountEmail email) {
+        this(email, true);
     }
 
-    public AccountEmailModelDao(final AccountEmail email) {
-        this(email.getId(), email.getCreatedDate(), email.getUpdatedDate(), email.getAccountId(), email.getEmail());
+    public AccountEmailModelDao(final AccountEmail email, final boolean isActive) {
+        super(email.getId(), email.getCreatedDate(), email.getUpdatedDate());
+        this.accountId = email.getAccountId();
+        this.email = email.getEmail();
+        this.isActive = isActive;
     }
 
     public UUID getAccountId() {
@@ -50,12 +50,17 @@ public class AccountEmailModelDao extends EntityBase implements EntityModelDao<A
         return email;
     }
 
+    public Boolean getIsActive() {
+        return isActive;
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("AccountEmailModelDao");
         sb.append("{accountId=").append(accountId);
         sb.append(", email='").append(email).append('\'');
+        sb.append(", isActive=").append(isActive);
         sb.append('}');
         return sb.toString();
     }
@@ -74,6 +79,9 @@ public class AccountEmailModelDao extends EntityBase implements EntityModelDao<A
 
         final AccountEmailModelDao that = (AccountEmailModelDao) o;
 
+        if (isActive != that.isActive) {
+            return false;
+        }
         if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
             return false;
         }
@@ -89,6 +97,7 @@ public class AccountEmailModelDao extends EntityBase implements EntityModelDao<A
         int result = super.hashCode();
         result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
         result = 31 * result + (email != null ? email.hashCode() : 0);
+        result = 31 * result + (isActive ? 1 : 0);
         return result;
     }
 
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailSqlDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailSqlDao.java
index 65344f1..90aa7c0 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailSqlDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailSqlDao.java
@@ -37,8 +37,8 @@ public interface AccountEmailSqlDao extends EntitySqlDao<AccountEmailModelDao, A
 
     @SqlUpdate
     @Audited(ChangeType.DELETE)
-    public void delete(@BindBean final AccountEmailModelDao accountEmail,
-                       @BindBean final InternalCallContext context);
+    public void markEmailAsDeleted(@BindBean final AccountEmailModelDao accountEmail,
+                                   @BindBean final InternalCallContext context);
 
     @SqlQuery
     public List<AccountEmailModelDao> getEmailByAccountId(@Bind("accountId") final UUID accountId,
diff --git a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
index dc3fe91..a5d6fd4 100644
--- a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2012 Ning, Inc.
  *
  * Ning licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -16,6 +16,7 @@
 
 package com.ning.billing.account.dao;
 
+import java.util.List;
 import java.util.UUID;
 
 import org.skife.jdbi.v2.IDBI;
@@ -176,4 +177,42 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
             }
         });
     }
+
+    @Override
+    public void addEmail(final AccountEmailModelDao email, final InternalCallContext context) throws AccountApiException {
+        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+            @Override
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                final AccountEmailSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountEmailSqlDao.class);
+
+                if (transactional.getById(email.getId().toString(), context) != null) {
+                    throw new AccountApiException(ErrorCode.ACCOUNT_EMAIL_ALREADY_EXISTS, email.getId());
+                }
+
+                transactional.create(email, context);
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public void removeEmail(final AccountEmailModelDao email, final InternalCallContext context) {
+        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+            @Override
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                entitySqlDaoWrapperFactory.become(AccountEmailSqlDao.class).markEmailAsDeleted(email, context);
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public List<AccountEmailModelDao> getEmailsByAccountId(final UUID accountId, final InternalTenantContext context) {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AccountEmailModelDao>>() {
+            @Override
+            public List<AccountEmailModelDao> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                return entitySqlDaoWrapperFactory.become(AccountEmailSqlDao.class).getEmailByAccountId(accountId, context);
+            }
+        });
+    }
 }
diff --git a/account/src/main/java/com/ning/billing/account/glue/DefaultAccountModule.java b/account/src/main/java/com/ning/billing/account/glue/DefaultAccountModule.java
index bbbce7c..20c88d0 100644
--- a/account/src/main/java/com/ning/billing/account/glue/DefaultAccountModule.java
+++ b/account/src/main/java/com/ning/billing/account/glue/DefaultAccountModule.java
@@ -22,9 +22,7 @@ import com.ning.billing.account.api.DefaultAccountService;
 import com.ning.billing.account.api.svcs.DefaultAccountInternalApi;
 import com.ning.billing.account.api.user.DefaultAccountUserApi;
 import com.ning.billing.account.dao.AccountDao;
-import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.account.dao.DefaultAccountDao;
-import com.ning.billing.account.dao.DefaultAccountEmailDao;
 import com.ning.billing.glue.AccountModule;
 import com.ning.billing.util.glue.RealImplementation;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
@@ -37,7 +35,6 @@ public class DefaultAccountModule extends AbstractModule implements AccountModul
     }
 
     protected void installAccountDao() {
-        bind(AccountEmailDao.class).to(DefaultAccountEmailDao.class).asEagerSingleton();
         bind(AccountDao.class).to(DefaultAccountDao.class).asEagerSingleton();
     }
 
diff --git a/account/src/main/resources/com/ning/billing/account/dao/AccountEmailSqlDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/AccountEmailSqlDao.sql.stg
index db12678..05bdcd2 100644
--- a/account/src/main/resources/com/ning/billing/account/dao/AccountEmailSqlDao.sql.stg
+++ b/account/src/main/resources/com/ning/billing/account/dao/AccountEmailSqlDao.sql.stg
@@ -7,6 +7,7 @@ historyTableName() ::= "account_email_history"
 tableFields(prefix) ::= <<
   account_id
 , email
+, is_active
 , created_by
 , created_date
 , updated_by
@@ -17,6 +18,7 @@ tableFields(prefix) ::= <<
 tableValues() ::= <<
   :accountId
 , :email
+, :isActive
 , :createdBy
 , :createdDate
 , :updatedBy
@@ -28,11 +30,15 @@ select
 <allTableFields()>
 from <tableName()>
 where account_id = :accountId
+and is_active
 <AND_CHECK_TENANT()>
 ;
 >>
 
-delete() ::= <<
-    DELETE FROM account_emails
-    WHERE id = :id <AND_CHECK_TENANT()>;
+markEmailAsDeleted() ::= <<
+update <tableName()>
+set is_active = 0
+where  id = :id
+<AND_CHECK_TENANT()>
+;
 >>
diff --git a/account/src/main/resources/com/ning/billing/account/ddl.sql b/account/src/main/resources/com/ning/billing/account/ddl.sql
index ef5a2ba..a509ae2 100644
--- a/account/src/main/resources/com/ning/billing/account/ddl.sql
+++ b/account/src/main/resources/com/ning/billing/account/ddl.sql
@@ -75,6 +75,7 @@ CREATE TABLE account_emails (
     id char(36) NOT NULL,
     account_id char(36) NOT NULL,
     email varchar(128) NOT NULL,
+    is_active bool DEFAULT true,
     created_by varchar(50) NOT NULL,
     created_date datetime NOT NULL,
     updated_by varchar(50) NOT NULL,
@@ -94,6 +95,7 @@ CREATE TABLE account_email_history (
     target_record_id int(11) unsigned NOT NULL,
     account_id char(36) NOT NULL,
     email varchar(128) NOT NULL,
+    is_active bool DEFAULT true,
     change_type char(6) NOT NULL,
     created_by varchar(50) NOT NULL,
     created_date datetime NOT NULL,
diff --git a/account/src/test/java/com/ning/billing/account/api/user/DefaultAccountUserApiTestWithDB.java b/account/src/test/java/com/ning/billing/account/api/user/DefaultAccountUserApiTestWithDB.java
index acbc9a3..091d07a 100644
--- a/account/src/test/java/com/ning/billing/account/api/user/DefaultAccountUserApiTestWithDB.java
+++ b/account/src/test/java/com/ning/billing/account/api/user/DefaultAccountUserApiTestWithDB.java
@@ -39,7 +39,7 @@ public class DefaultAccountUserApiTestWithDB extends AccountDaoTestBase {
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
         final DefaultCallContextFactory callContextFactory = new DefaultCallContextFactory(clock);
-        accountUserApi = new DefaultAccountUserApi(callContextFactory, internalCallContextFactory, accountDao, accountEmailDao);
+        accountUserApi = new DefaultAccountUserApi(callContextFactory, internalCallContextFactory, accountDao);
     }
 
     @Test(groups = "slow")
diff --git a/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java b/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
index 0f4392e..914a41d 100644
--- a/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
+++ b/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
@@ -32,10 +32,8 @@ import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.api.DefaultAccountEmail;
 import com.ning.billing.account.api.DefaultBillCycleDay;
 import com.ning.billing.account.dao.AccountDao;
-import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.account.dao.MockAccountDao;
-import com.ning.billing.account.dao.MockAccountEmailDao;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;
@@ -51,14 +49,12 @@ public class TestDefaultAccountUserApi extends AccountTestSuite {
     private final InternalTenantContext tenantContext = Mockito.mock(InternalTenantContext.class);
 
     private AccountDao accountDao;
-    private AccountEmailDao accountEmailDao;
     private DefaultAccountUserApi accountUserApi;
 
     @BeforeMethod(groups = "fast")
     public void setUp() throws Exception {
         accountDao = new MockAccountDao(Mockito.mock(InternalBus.class));
-        accountEmailDao = new MockAccountEmailDao();
-        accountUserApi = new DefaultAccountUserApi(factory, internalFactory, accountDao, accountEmailDao);
+        accountUserApi = new DefaultAccountUserApi(factory, internalFactory, accountDao);
     }
 
     @Test(groups = "fast")
@@ -117,22 +113,22 @@ public class TestDefaultAccountUserApi extends AccountTestSuite {
         final UUID accountId = UUID.randomUUID();
 
         // Verify the initial state
-        Assert.assertEquals(accountEmailDao.getByAccountId(accountId, tenantContext).size(), 0);
+        Assert.assertEquals(accountDao.getEmailsByAccountId(accountId, tenantContext).size(), 0);
 
         // Add the first email
         final String emailAddress1 = UUID.randomUUID().toString();
         final AccountEmail email1 = new DefaultAccountEmail(accountId, emailAddress1);
         accountUserApi.addEmail(accountId, email1, callContext);
-        Assert.assertEquals(accountEmailDao.getByAccountId(accountId, tenantContext).size(), 1);
+        Assert.assertEquals(accountDao.getEmailsByAccountId(accountId, tenantContext).size(), 1);
 
         // Add a second one
         final String emailAddress2 = UUID.randomUUID().toString();
         final AccountEmail email2 = new DefaultAccountEmail(accountId, emailAddress2);
         accountUserApi.addEmail(accountId, email2, callContext);
-        Assert.assertEquals(accountEmailDao.getByAccountId(accountId, tenantContext).size(), 2);
+        Assert.assertEquals(accountDao.getEmailsByAccountId(accountId, tenantContext).size(), 2);
 
         // Remove the first second one
         accountUserApi.removeEmail(accountId, email1, callContext);
-        Assert.assertEquals(accountEmailDao.getByAccountId(accountId, tenantContext).size(), 1);
+        Assert.assertEquals(accountDao.getEmailsByAccountId(accountId, tenantContext).size(), 1);
     }
 }
diff --git a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
index 3b7b32f..5e99eb6 100644
--- a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
+++ b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
@@ -42,7 +42,6 @@ public abstract class AccountDaoTestBase extends AccountTestSuiteWithEmbeddedDB 
     protected final Clock clock = new ClockMock();
 
     protected AccountDao accountDao;
-    protected AccountEmailDao accountEmailDao;
     protected InternalCallContextFactory internalCallContextFactory;
     protected IDBI dbi;
     protected InternalBus bus;
@@ -60,10 +59,6 @@ public abstract class AccountDaoTestBase extends AccountTestSuiteWithEmbeddedDB 
             accountDao = new DefaultAccountDao(dbi, bus, internalCallContextFactory);
             // Health check test to make sure MySQL is setup properly
             accountDao.test(internalCallContext);
-
-            accountEmailDao = new DefaultAccountEmailDao(dbi);
-            // Health check test to make sure MySQL is setup properly
-            accountEmailDao.test(internalCallContext);
         } catch (Throwable t) {
             fail(t.toString());
         }
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 ea89b8b..6940c41 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,12 +16,17 @@
 
 package com.ning.billing.account.dao;
 
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
+import org.testng.Assert;
+
+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.AccountEmail;
 import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.api.DefaultMutableAccountData;
 import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
@@ -34,10 +39,14 @@ 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.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
 
 public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account, AccountApiException> implements AccountDao {
 
+    private final MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException> accountEmailSqlDao = new MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException>();
     private final InternalBus eventBus;
 
     @Inject
@@ -109,4 +118,28 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account, 
 
         update(new AccountModelDao(accountId, updatedAccount), context);
     }
+
+    @Override
+    public void addEmail(final AccountEmailModelDao email, final InternalCallContext context) {
+        try {
+            accountEmailSqlDao.create(email, context);
+        } catch (BillingExceptionBase billingExceptionBase) {
+            Assert.fail(billingExceptionBase.toString());
+        }
+    }
+
+    @Override
+    public void removeEmail(final AccountEmailModelDao email, final InternalCallContext context) {
+        accountEmailSqlDao.delete(email, context);
+    }
+
+    @Override
+    public List<AccountEmailModelDao> getEmailsByAccountId(final UUID accountId, final InternalTenantContext context) {
+        return ImmutableList.<AccountEmailModelDao>copyOf(Collections2.filter(accountEmailSqlDao.get(context), new Predicate<AccountEmailModelDao>() {
+            @Override
+            public boolean apply(final AccountEmailModelDao input) {
+                return input.getAccountId().equals(accountId);
+            }
+        }));
+    }
 }
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
index 3b9d32c..95c0653 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
@@ -346,14 +346,14 @@ public class TestAccountDao extends AccountDaoTestBase {
     public void testHandleDuplicateEmails() throws AccountApiException {
         final UUID accountId = UUID.randomUUID();
         final AccountEmail email = new DefaultAccountEmail(accountId, "test@gmail.com");
-        Assert.assertEquals(accountEmailDao.getByAccountId(accountId, internalCallContext).size(), 0);
+        Assert.assertEquals(accountDao.getEmailsByAccountId(accountId, internalCallContext).size(), 0);
 
         final AccountEmailModelDao accountEmailModelDao = new AccountEmailModelDao(email);
-        accountEmailDao.create(accountEmailModelDao, internalCallContext);
-        Assert.assertEquals(accountEmailDao.getByAccountId(accountId, internalCallContext).size(), 1);
+        accountDao.addEmail(accountEmailModelDao, internalCallContext);
+        Assert.assertEquals(accountDao.getEmailsByAccountId(accountId, internalCallContext).size(), 1);
 
         try {
-            accountEmailDao.create(accountEmailModelDao, internalCallContext);
+            accountDao.addEmail(accountEmailModelDao, internalCallContext);
             Assert.fail();
         } catch (TransactionFailedException e) {
             Assert.assertTrue(e.getCause() instanceof AccountApiException);
@@ -370,8 +370,8 @@ public class TestAccountDao extends AccountDaoTestBase {
 
         // add a new e-mail
         final AccountEmail email = new DefaultAccountEmail(accountId, "test@gmail.com");
-        accountEmailDao.create(new AccountEmailModelDao(email), internalCallContext);
-        emails = accountEmailDao.getByAccountId(accountId, internalCallContext);
+        accountDao.addEmail(new AccountEmailModelDao(email), internalCallContext);
+        emails = accountDao.getEmailsByAccountId(accountId, internalCallContext);
         assertEquals(emails.size(), 1);
 
         // verify that audit contains one entry
@@ -381,9 +381,9 @@ public class TestAccountDao extends AccountDaoTestBase {
         //assertEquals(auditLogs.size(), 1);
 
         // delete e-mail
-        accountEmailDao.delete(new AccountEmailModelDao(email), internalCallContext);
+        accountDao.removeEmail(new AccountEmailModelDao(email), internalCallContext);
 
-        emails = accountEmailDao.getByAccountId(accountId, internalCallContext);
+        emails = accountDao.getEmailsByAccountId(accountId, internalCallContext);
         assertEquals(emails.size(), 0);
     }
 
@@ -394,20 +394,20 @@ public class TestAccountDao extends AccountDaoTestBase {
         final String email2 = UUID.randomUUID().toString();
 
         // Verify the original state
-        assertEquals(accountEmailDao.getByAccountId(accountId, internalCallContext).size(), 0);
+        assertEquals(accountDao.getEmailsByAccountId(accountId, internalCallContext).size(), 0);
 
         // Add a new e-mail
         final AccountEmail accountEmail1 = new DefaultAccountEmail(accountId, email1);
-        accountEmailDao.create(new AccountEmailModelDao(accountEmail1), internalCallContext);
-        final List<AccountEmailModelDao> firstEmails = accountEmailDao.getByAccountId(accountId, internalCallContext);
+        accountDao.addEmail(new AccountEmailModelDao(accountEmail1), internalCallContext);
+        final List<AccountEmailModelDao> firstEmails = accountDao.getEmailsByAccountId(accountId, internalCallContext);
         assertEquals(firstEmails.size(), 1);
         assertEquals(firstEmails.get(0).getAccountId(), accountId);
         assertEquals(firstEmails.get(0).getEmail(), email1);
 
         // Add a second e-mail
         final AccountEmail accountEmail2 = new DefaultAccountEmail(accountId, email2);
-        accountEmailDao.create(new AccountEmailModelDao(accountEmail2), internalCallContext);
-        final List<AccountEmailModelDao> secondEmails = accountEmailDao.getByAccountId(accountId, internalCallContext);
+        accountDao.addEmail(new AccountEmailModelDao(accountEmail2), internalCallContext);
+        final List<AccountEmailModelDao> secondEmails = accountDao.getEmailsByAccountId(accountId, internalCallContext);
         assertEquals(secondEmails.size(), 2);
         assertTrue(secondEmails.get(0).getAccountId().equals(accountId));
         assertTrue(secondEmails.get(1).getAccountId().equals(accountId));
@@ -415,8 +415,8 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertTrue(secondEmails.get(1).getEmail().equals(email1) || secondEmails.get(1).getEmail().equals(email2));
 
         // Delete the first e-mail
-        accountEmailDao.delete(new AccountEmailModelDao(accountEmail1), internalCallContext);
-        final List<AccountEmailModelDao> thirdEmails = accountEmailDao.getByAccountId(accountId, internalCallContext);
+        accountDao.removeEmail(new AccountEmailModelDao(accountEmail1), internalCallContext);
+        final List<AccountEmailModelDao> thirdEmails = accountDao.getEmailsByAccountId(accountId, internalCallContext);
         assertEquals(thirdEmails.size(), 1);
         assertEquals(thirdEmails.get(0).getAccountId(), accountId);
         assertEquals(thirdEmails.get(0).getEmail(), email2);
diff --git a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
index 226f505..23740f0 100644
--- a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
+++ b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
@@ -16,10 +16,7 @@
 
 package com.ning.billing.account.glue;
 
-import org.mockito.Mockito;
-
 import com.ning.billing.account.dao.AccountDao;
-import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.account.dao.MockAccountDao;
 import com.ning.billing.mock.glue.MockClockModule;
 import com.ning.billing.util.glue.CallContextModule;
@@ -29,8 +26,6 @@ public class AccountModuleWithMocks extends DefaultAccountModule {
     @Override
     protected void installAccountDao() {
         bind(MockAccountDao.class).asEagerSingleton();
-        final AccountEmailDao accountEmailDao = Mockito.mock(AccountEmailDao.class);
-        bind(AccountEmailDao.class).toInstance(accountEmailDao);
         bind(AccountDao.class).to(MockAccountDao.class);
     }
 
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
index 4d9a939..84e5d3d 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
@@ -31,9 +31,7 @@ import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.account.api.svcs.DefaultAccountInternalApi;
 import com.ning.billing.account.api.user.DefaultAccountUserApi;
 import com.ning.billing.account.dao.AccountDao;
-import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.account.dao.DefaultAccountDao;
-import com.ning.billing.account.dao.DefaultAccountEmailDao;
 import com.ning.billing.analytics.dao.BusinessAccountTagSqlDao;
 import com.ning.billing.analytics.dao.BusinessInvoicePaymentTagSqlDao;
 import com.ning.billing.analytics.dao.BusinessInvoiceTagSqlDao;
@@ -42,8 +40,6 @@ import com.ning.billing.catalog.DefaultCatalogService;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.io.VersionedCatalogLoader;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.config.CatalogConfig;
 import com.ning.billing.entitlement.alignment.PlanAligner;
 import com.ning.billing.entitlement.api.svcs.DefaultEntitlementInternalApi;
 import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
@@ -58,7 +54,9 @@ import com.ning.billing.mock.MockAccountBuilder;
 import com.ning.billing.util.bus.InMemoryInternalBus;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
+import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.config.CatalogConfig;
 import com.ning.billing.util.notificationq.DefaultNotificationQueueService;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
 import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
@@ -85,11 +83,10 @@ public class TestBusinessTagRecorder extends AnalyticsTestSuiteWithEmbeddedDB {
         subscriptionTransitionTagSqlDao = dbi.onDemand(BusinessSubscriptionTransitionTagSqlDao.class);
         eventBus = new InMemoryInternalBus();
         final AccountDao accountDao = new DefaultAccountDao(dbi, eventBus, new InternalCallContextFactory(dbi, new ClockMock()));
-        final AccountEmailDao accountEmailDao = new DefaultAccountEmailDao(dbi);
         callContextFactory = new DefaultCallContextFactory(clock);
         final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(dbi, clock);
-        accountApi = new DefaultAccountInternalApi(accountDao, accountEmailDao);
-        accountUserApi = new DefaultAccountUserApi(callContextFactory, internalCallContextFactory, accountDao, accountEmailDao);
+        accountApi = new DefaultAccountInternalApi(accountDao);
+        accountUserApi = new DefaultAccountUserApi(callContextFactory, internalCallContextFactory, accountDao);
         final CatalogService catalogService = new DefaultCatalogService(Mockito.mock(CatalogConfig.class), Mockito.mock(VersionedCatalogLoader.class));
         final AddonUtils addonUtils = new AddonUtils(catalogService);
         final DefaultNotificationQueueService notificationQueueService = new DefaultNotificationQueueService(dbi, clock, internalCallContextFactory);
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntityDaoBase.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntityDaoBase.java
index cfa095e..e4718c3 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntityDaoBase.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntityDaoBase.java
@@ -41,14 +41,13 @@ public abstract class EntityDaoBase<M extends EntityModelDao<E>, E extends Entit
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                final EntitySqlDao<M, E> transactional = entitySqlDaoWrapperFactory.become(realSqlDao);
 
-                if (getById(entity.getId(), context) != null) {
+                if (transactional.getById(entity.getId().toString(), context) != null) {
                     throw generateAlreadyExistsException(entity, context);
                 }
-                final EntitySqlDao<M, E> transactional = entitySqlDaoWrapperFactory.become(realSqlDao);
                 transactional.create(entity, context);
 
-
                 final M refreshedEntity = transactional.getById(entity.getId().toString(), context);
 
                 postBusEventFromTransaction(entity, refreshedEntity, ChangeType.INSERT, entitySqlDaoWrapperFactory, context);