killbill-aplcache

Unit test work for audit refactoring

11/8/2012 12:59:13 AM

Changes

Details

diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java
index a704198..866063c 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java
@@ -40,7 +40,7 @@ public @interface AccountEmailHistoryBinder {
             return new Binder<AccountEmailHistoryBinder, EntityHistory<AccountEmail>>() {
                 @Override
                 public void bind(final SQLStatement<?> q, final AccountEmailHistoryBinder bind, final EntityHistory<AccountEmail> history) {
-                    q.bind("recordId", history.getValue());
+                    //q.bind("recordId", history.getValue());
                     q.bind("changeType", history.getChangeType().toString());
 
                     final AccountEmail accountEmail = history.getEntity();
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java b/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java
index 7e99fa6..7c70303 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java
@@ -42,7 +42,7 @@ public @interface AccountHistoryBinder {
             return new Binder<AccountHistoryBinder, EntityHistory<Account>>() {
                 @Override
                 public void bind(final SQLStatement<?> q, final AccountHistoryBinder bind, final EntityHistory<Account> history) {
-                    q.bind("recordId", history.getValue());
+                    //q.bind("recordId", history.getValue());
                     q.bind("changeType", history.getChangeType().toString());
 
                     final Account account = history.getEntity();
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 3b005ce..d7913c0 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
@@ -167,7 +167,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         final TagDao tagDao = new AuditedTagDao(dbi, tagEventBuilder, bus, new DefaultClock());
         tagDao.insertTag(account.getId(), ObjectType.ACCOUNT, definition.getId(), internalCallContext);
 
-        final Map<String, Tag> tagMap = tagDao.loadEntities(account.getId(), ObjectType.ACCOUNT, internalCallContext);
+        final Map<String, Tag> tagMap = tagDao.getTags(account.getId(), ObjectType.ACCOUNT, internalCallContext);
         assertEquals(tagMap.size(), 1);
 
         assertEquals(tagMap.values().iterator().next().getTagDefinitionId(), definition.getId());
diff --git a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
index fe98ad6..dc32253 100644
--- a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
+++ b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
@@ -65,4 +65,13 @@ public enum ControlTagType {
     public List<ObjectType> getApplicableObjectTypes() {
         return applicableObjectTypes;
     }
+
+    public static ControlTagType getTypeFromId(final UUID targetId) {
+        for (ControlTagType cur : values()) {
+            if (cur.getId().equals(targetId)) {
+                return cur;
+            }
+        }
+        return null;
+    }
 }
diff --git a/api/src/main/java/com/ning/billing/util/tag/Tag.java b/api/src/main/java/com/ning/billing/util/tag/Tag.java
index 553ef5f..3c6f36d 100644
--- a/api/src/main/java/com/ning/billing/util/tag/Tag.java
+++ b/api/src/main/java/com/ning/billing/util/tag/Tag.java
@@ -18,8 +18,14 @@ package com.ning.billing.util.tag;
 
 import java.util.UUID;
 
+import com.ning.billing.ObjectType;
 import com.ning.billing.util.entity.Entity;
 
 public interface Tag extends Entity {
+
     UUID getTagDefinitionId();
+
+    ObjectType getObjectType();
+
+    UUID getObjectId();
 }
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java b/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java
index f9d9583..5f3542b 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java
@@ -28,10 +28,13 @@ import org.joda.time.LocalDate;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.ning.billing.ObjectType;
 import com.ning.billing.junction.api.Blockable;
 import com.ning.billing.overdue.OverdueTestSuite;
 import com.ning.billing.overdue.config.api.BillingState;
 import com.ning.billing.overdue.config.api.PaymentResponse;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.catalog.XMLLoader;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.DefaultControlTag;
@@ -43,6 +46,8 @@ public class TestCondition extends OverdueTestSuite {
     @XmlRootElement(name = "condition")
     private static class MockCondition extends DefaultCondition<Blockable> {}
 
+    private Clock clock = new ClockMock();
+
     @Test(groups = "fast")
     public void testNumberOfUnpaidInvoicesEqualsOrExceeds() throws Exception {
         final String xml =
@@ -147,16 +152,24 @@ public class TestCondition extends OverdueTestSuite {
 
         final LocalDate now = new LocalDate();
 
-        final BillingState<Blockable> state0 = new BillingState<Blockable>(new UUID(0L, 1L), 0, BigDecimal.ZERO, null,
-                                                                           DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.LOST_OR_STOLEN_CARD, new Tag[]{new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF), new DescriptiveTag(UUID.randomUUID())});
-        final BillingState<Blockable> state1 = new BillingState<Blockable>(new UUID(0L, 1L), 1, new BigDecimal("100.00"), now.minusDays(10),
-                                                                           DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF)});
-        final BillingState<Blockable> state2 = new BillingState<Blockable>(new UUID(0L, 1L), 1, new BigDecimal("200.00"), now.minusDays(20),
+        final ObjectType objectType = ObjectType.BUNDLE;
+
+        final UUID objectId = new UUID(0L, 1L);
+        final BillingState<Blockable> state0 = new BillingState<Blockable>(objectId, 0, BigDecimal.ZERO, null,
+                                                                           DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.LOST_OR_STOLEN_CARD,
+                                                                           new Tag[]{new DefaultControlTag( ControlTagType.AUTO_INVOICING_OFF, objectType, objectId, clock.getUTCNow()),
+                                                                                   new DescriptiveTag(UUID.randomUUID(), objectType, objectId, clock.getUTCNow())});
+
+        final BillingState<Blockable> state1 = new BillingState<Blockable>(objectId, 1, new BigDecimal("100.00"), now.minusDays(10),
+                                                                           DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS,
+                                                                           new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF, objectType, objectId, clock.getUTCNow())});
+
+        final BillingState<Blockable> state2 = new BillingState<Blockable>(objectId, 1, new BigDecimal("200.00"), now.minusDays(20),
                                                                            DateTimeZone.UTC, unpaidInvoiceId,
                                                                            PaymentResponse.DO_NOT_HONOR,
-                                                                           new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF),
-                                                                                     new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF),
-                                                                                     new DescriptiveTag(UUID.randomUUID())});
+                                                                           new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF, objectType, objectId, clock.getUTCNow()),
+                                                                                     new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF, objectType, objectId, clock.getUTCNow()),
+                                                                                     new DescriptiveTag(UUID.randomUUID(), objectType, objectId, clock.getUTCNow())});
 
         Assert.assertTrue(!c.evaluate(state0, now));
         Assert.assertTrue(c.evaluate(state1, now));
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java
index dc59070..e49cfa5 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java
@@ -41,7 +41,7 @@ public @interface PaymentAttemptHistoryBinder {
             return new Binder<PaymentAttemptHistoryBinder, EntityHistory<PaymentAttemptModelDao>>() {
                 @Override
                 public void bind(final SQLStatement<?> q, final PaymentAttemptHistoryBinder bind, final EntityHistory<PaymentAttemptModelDao> history) {
-                    q.bind("recordId", history.getValue());
+                  //  q.bind("recordId", history.getValue());
                     q.bind("changeType", history.getChangeType().toString());
                     final PaymentAttemptModelDao attempt = history.getEntity();
                     q.bind("id", attempt.getId().toString());
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java
index a6db584..e2caa01 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java
@@ -39,7 +39,7 @@ public @interface PaymentHistoryBinder {
             return new Binder<PaymentHistoryBinder, EntityHistory<PaymentModelDao>>() {
                 @Override
                 public void bind(final SQLStatement<?> q, final PaymentHistoryBinder bind, final EntityHistory<PaymentModelDao> history) {
-                    q.bind("recordId", history.getValue());
+                   // q.bind("recordId", history.getValue());
                     q.bind("changeType", history.getChangeType().toString());
                     final PaymentModelDao payment = history.getEntity();
                     q.bind("id", payment.getId().toString());
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodHistoryBinder.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodHistoryBinder.java
index b74d528..c540dab 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodHistoryBinder.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodHistoryBinder.java
@@ -39,7 +39,7 @@ public @interface PaymentMethodHistoryBinder {
             return new Binder<PaymentMethodHistoryBinder, EntityHistory<PaymentMethodModelDao>>() {
                 @Override
                 public void bind(final SQLStatement<?> q, final PaymentMethodHistoryBinder bind, final EntityHistory<PaymentMethodModelDao> history) {
-                    q.bind("recordId", history.getValue());
+                   // q.bind("recordId", history.getValue());
                     q.bind("changeType", history.getChangeType().toString());
                     final PaymentMethodModelDao paymentMethod = history.getEntity();
                     q.bind("id", paymentMethod.getId().toString());
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/RefundHistoryBinder.java b/payment/src/main/java/com/ning/billing/payment/dao/RefundHistoryBinder.java
index 3110b2f..02a1543 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/RefundHistoryBinder.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/RefundHistoryBinder.java
@@ -42,7 +42,7 @@ public @interface RefundHistoryBinder {
             return new Binder<RefundHistoryBinder, EntityHistory<RefundModelDao>>() {
                 @Override
                 public void bind(final SQLStatement<?> q, final RefundHistoryBinder bind, final EntityHistory<RefundModelDao> history) {
-                    q.bind("recordId", history.getValue());
+                   // q.bind("recordId", history.getValue());
                     q.bind("changeType", history.getChangeType().toString());
                     final RefundModelDao refund = history.getEntity();
                     q.bind("id", refund.getId().toString());
diff --git a/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java b/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
index 926ddfd..fdfd8a8 100644
--- a/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
+++ b/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
@@ -64,14 +64,16 @@ public class DefaultAuditDao implements AuditDao {
     private List<AuditLog> doGetAuditLogsViaHistoryForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel, final InternalTenantContext context) {
         final List<AuditLog> auditLogs = new ArrayList<AuditLog>();
 
+        Long targetRecordId = auditSqlDao.getRecordIdForTable(tableName.getTableName().toLowerCase(), objectId.toString(), context);
+
         // Look at the history table and gather all the history_record_id for that objectId
-        final List<Long> targetRecordIds = auditSqlDao.getHistoryRecordIdsForTable(tableName.getHistoryTableName().getTableName().toLowerCase(),
-                                                                             objectId.toString(), context);
-        if (targetRecordIds == null) {
+        final List<Long> recordIds = auditSqlDao.getHistoryRecordIdsForTable(tableName.getHistoryTableName().getTableName().toLowerCase(),
+                                                                             targetRecordId, context);
+        if (recordIds == null) {
             return auditLogs;
         } else {
-            for (final Long targetRecordId : targetRecordIds) {
-                auditLogs.addAll(getAuditLogsForRecordId(tableName.getHistoryTableName(), targetRecordId, auditLevel, context));
+            for (final Long recordId : recordIds) {
+                auditLogs.addAll(getAuditLogsForRecordId(tableName.getHistoryTableName(), recordId, auditLevel, context));
             }
 
             return auditLogs;
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
index 69b4f30..9f30dc1 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
@@ -188,7 +188,9 @@ public abstract class AuditedCollectionDaoBase<T extends Entity, V> implements A
             if (recordId == null) {
                 throw new IllegalStateException("recordId for object " + entity.getClass() + " is null ");
             }
+            /*
             histories.add(new EntityHistory<T>(id, recordId, entity, changeType));
+            */
         }
 
         return histories;
@@ -198,7 +200,7 @@ public abstract class AuditedCollectionDaoBase<T extends Entity, V> implements A
         final List<EntityAudit> audits = new ArrayList<EntityAudit>();
 
         for (final EntityHistory<T> history : histories) {
-            final Long recordId = history.getValue();
+            final Long recordId = null; // history.getValue();
             final Long historyRecordId = historyRecordIds.get(recordId);
             audits.add(new EntityAudit(getTableName(context), historyRecordId, history.getChangeType(), clock.getUTCNow()));
         }
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditLogMapper.java b/util/src/main/java/com/ning/billing/util/dao/AuditLogMapper.java
index 418ce29..23dd0ea 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditLogMapper.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditLogMapper.java
@@ -39,14 +39,14 @@ public class AuditLogMapper extends MapperBase implements ResultSetMapper<AuditL
         final long targetRecordId = r.getLong("target_record_id");
         final String changeType = r.getString("change_type");
         final DateTime createdDate = getDateTime(r, "created_date");
-        final String changedBy = r.getString("changed_by");
+        final String createdBy = r.getString("created_by");
         final String reasonCode = r.getString("reason_code");
         final String comments = r.getString("comments");
         final UUID userToken = getUUID(r, "user_token");
 
         final EntityAudit entityAudit = new EntityAudit(id, TableName.valueOf(tableName), targetRecordId, ChangeType.valueOf(changeType), createdDate);
         // TODO - we have the tenant_record_id but not the tenant id here
-        final CallContext callContext = new DefaultCallContext(null, changedBy, createdDate, reasonCode, comments, userToken);
+        final CallContext callContext = new DefaultCallContext(null, createdBy, createdDate, reasonCode, comments, userToken);
         return new DefaultAuditLog(entityAudit, callContext);
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java b/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
index 55a35c5..094169b 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
@@ -31,8 +31,10 @@ import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.callcontext.InternalTenantContextBinder;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
+import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 
-@ExternalizedSqlViaStringTemplate3
+@EntitySqlDaoStringTemplate("/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg")
 @RegisterMapper(AuditLogMapper.class)
 public interface AuditSqlDao {
 
@@ -45,24 +47,24 @@ public interface AuditSqlDao {
                                            @BindBean final InternalCallContext context);
 
     @SqlQuery
-    public List<AuditLog> getAuditLogsForTargetRecordId(@TableNameBinder final TableName tableName,
+    public List<AuditLog> getAuditLogsForTargetRecordId(@BindBean final TableName tableName,
                                                         @Bind("targetRecordId") final long targetRecordId,
-                                                        @InternalTenantContextBinder final InternalTenantContext context);
+                                                        @BindBean final InternalTenantContext context);
 
     @SqlQuery
-    public Long getRecordId(@Bind("id") final String id, @InternalTenantContextBinder final InternalTenantContext context);
+    public Long getRecordId(@Bind("id") final String id, @BindBean final InternalTenantContext context);
 
     @SqlQuery
     public Long getRecordIdForTable(@Define("tableName") final String tableName,
                                     @Bind("id") final String id,
-                                    @InternalTenantContextBinder final InternalTenantContext context);
+                                    @BindBean final InternalTenantContext context);
 
     @SqlQuery
-    public List<Long> getHistoryRecordIdsForTable(@Define("tableName") final String tableName,
-                                                  @Bind("id") final String id,
-                                                  @InternalTenantContextBinder final InternalTenantContext context);
+    public List<Long> getHistoryRecordIdsForTable(@Define("historyTableName") final String historyTableName,
+                                                  @Bind("targetRecordId") final Long targetRecordId,
+                                                  @BindBean final InternalTenantContext context);
 
     @SqlQuery
     public Long getHistoryRecordId(@Bind("recordId") final Long recordId,
-                                   @InternalTenantContextBinder final InternalTenantContext context);
+                                   @BindBean final InternalTenantContext context);
 }
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index a7a7018..d3cc502 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -33,7 +33,6 @@ import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.dao.EntityAudit;
 import com.ning.billing.util.dao.EntityHistory;
-import com.ning.billing.util.dao.EntityHistoryToBeRenamed;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.Entity;
 
@@ -219,20 +218,19 @@ public class EntitySqlDaoWrapperInvocationHandler<T extends EntitySqlDao<U>, U e
     }
 
     private Long insertHistory(final Long entityRecordId, final U entity, final ChangeType changeType, final InternalCallContext context) {
-
         // TODO use clock
         EntityHistory<U> history = new EntityHistory<U>(entity, entityRecordId, changeType, context.getCreatedDate());
 
         sqlDao.addHistoryFromTransaction(history, context);
         return sqlDao.getHistoryRecordId(entityRecordId, context);
-
     }
 
 
 
     private void insertAudits(final TableName tableName, final Long historyRecordId, final ChangeType changeType, final InternalCallContext context) {
         // STEPH can we trust context or should we use Clock?
-        final EntityAudit audit = new EntityAudit(tableName, historyRecordId, changeType, context.getCreatedDate());
+        final TableName destinationTableName = Objects.firstNonNull(tableName.getHistoryTableName(), tableName);
+        final EntityAudit audit = new EntityAudit(destinationTableName, historyRecordId, changeType, context.getCreatedDate());
         sqlDao.insertAuditFromTransaction(audit, context);
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/svcapi/tag/DefaultTagInternalApi.java b/util/src/main/java/com/ning/billing/util/svcapi/tag/DefaultTagInternalApi.java
index 3c7f8d4..6bbc8eb 100644
--- a/util/src/main/java/com/ning/billing/util/svcapi/tag/DefaultTagInternalApi.java
+++ b/util/src/main/java/com/ning/billing/util/svcapi/tag/DefaultTagInternalApi.java
@@ -50,7 +50,7 @@ public class DefaultTagInternalApi implements TagInternalApi {
     @Override
     public Map<String, Tag> getTags(UUID objectId, ObjectType objectType,
             InternalTenantContext context) {
-        return tagDao.loadEntities(objectId, objectType, context);
+        return tagDao.getTags(objectId, objectType, context);
     }
 
     @Override
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
index e927d84..52cd460 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
@@ -103,7 +103,7 @@ public class DefaultTagUserApi implements TagUserApi {
 
     @Override
     public Map<String, Tag> getTags(final UUID objectId, final ObjectType objectType, final TenantContext context) {
-        return tagDao.loadEntities(objectId, objectType, internalCallContextFactory.createInternalTenantContext(context));
+        return tagDao.getTags(objectId, objectType, internalCallContextFactory.createInternalTenantContext(context));
     }
 
     @Override
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
index 4638e3b..06469ab 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
@@ -16,65 +16,61 @@
 
 package com.ning.billing.util.tag.dao;
 
-import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
 import org.skife.jdbi.v2.IDBI;
-import org.skife.jdbi.v2.Transaction;
-import org.skife.jdbi.v2.TransactionStatus;
-import org.skife.jdbi.v2.exceptions.TransactionFailedException;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.api.TagApiException;
-import com.ning.billing.util.api.TagDefinitionApiException;
-import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.dao.AuditedCollectionDaoBase;
-import com.ning.billing.util.dao.EntityAudit;
-import com.ning.billing.util.dao.EntityHistory;
-import com.ning.billing.util.dao.Mapper;
-import com.ning.billing.util.dao.TableName;
-import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
+import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
+import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
+import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 import com.ning.billing.util.events.TagInternalEvent;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.DefaultControlTag;
 import com.ning.billing.util.tag.DefaultTagDefinition;
+import com.ning.billing.util.tag.DescriptiveTag;
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.user.TagEventBuilder;
 
 import com.google.inject.Inject;
 
-public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements TagDao {
+public class AuditedTagDao implements TagDao {
 
     private static final Logger log = LoggerFactory.getLogger(AuditedTagDao.class);
 
+    private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
     private final TagSqlDao tagSqlDao;
     private final TagEventBuilder tagEventBuilder;
     private final InternalBus bus;
+    private final Clock clock;
 
     @Inject
     public AuditedTagDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final InternalBus bus, final Clock clock) {
-        super(clock);
+        this.clock = clock;
         this.tagEventBuilder = tagEventBuilder;
         this.bus = bus;
         this.tagSqlDao = dbi.onDemand(TagSqlDao.class);
+        this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi);
     }
 
-    @Override
     protected Tag getEquivalenceObjectFor(final Tag obj) {
         return obj;
     }
 
-    private TagDefinition getTagDefinitionFromTransaction(final UUID tagDefinitionId, final InternalTenantContext context) throws TagApiException {
+    private TagDefinition getTagDefinitionFromTransaction(final UUID tagDefinitionId, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) throws TagApiException {
         TagDefinition tagDefintion = null;
         for (final ControlTagType t : ControlTagType.values()) {
             if (t.getId().equals(tagDefinitionId)) {
@@ -83,7 +79,7 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements
             }
         }
         if (tagDefintion == null) {
-            final TagDefinitionSqlDao transTagDefintionSqlDao = tagSqlDao.become(TagDefinitionSqlDao.class);
+            final TagDefinitionSqlDao transTagDefintionSqlDao = entitySqlDaoWrapperFactory.become(TagDefinitionSqlDao.class);
             tagDefintion = transTagDefintionSqlDao.getById(tagDefinitionId.toString(), context);
         }
 
@@ -94,35 +90,34 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements
     }
 
     @Override
+    public Tag getTagById(final UUID tagId, final InternalTenantContext context) {
+        return tagSqlDao.getById(tagId.toString(), context);
+    }
+
+    @Override
+    public Map<String, Tag> getTags(final UUID objectId, final ObjectType objectType, final InternalTenantContext internalTenantContext) {
+        List<Tag> tags = tagSqlDao.getTagsForObject(objectId, objectType, internalTenantContext);
+        Map<String, Tag> result = new HashMap<String, Tag>();
+        for (Tag cur : tags) {
+            result.put(cur.getId().toString(), cur);
+        }
+        return result;
+    }
+
+    @Override
     public void insertTag(final UUID objectId, final ObjectType objectType, final UUID tagDefinitionId, final InternalCallContext context)
             throws TagApiException {
-        tagSqlDao.inTransaction(new Transaction<Void, TagSqlDao>() {
+        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
-            public Void inTransaction(final TagSqlDao transTagSqlDao, final TransactionStatus status) throws Exception {
-
-                final String tagId = UUID.randomUUID().toString();
-                final TagDefinition tagDefinition = getTagDefinitionFromTransaction(tagDefinitionId, context);
-
-                // Create the tag
-                tagSqlDao.addTagFromTransaction(tagId, tagDefinitionId.toString(), objectId.toString(), objectType, context);
-
-                final Tag tag = tagSqlDao.findTag(tagDefinitionId.toString(), objectId.toString(), objectType, context);
-                final List<Tag> tagList = Arrays.asList(tag);
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
 
-                // Gather the tag ids for this object id
-                final List<Mapper<UUID, Long>> recordIds = tagSqlDao.getRecordIds(objectId.toString(), objectType, context);
-                final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds, objectType);
+                final TagDefinition tagDefinition = getTagDefinitionFromTransaction(tagDefinitionId, entitySqlDaoWrapperFactory, context);
 
-                // Update the history table
-                final List<EntityHistory<Tag>> entityHistories = convertToHistory(tagList, recordIdMap, ChangeType.INSERT);
-                final Long maxHistoryRecordId = tagSqlDao.getMaxHistoryRecordId(context);
-                tagSqlDao.addHistoryFromTransaction(objectId.toString(), objectType, entityHistories, context);
+                final Tag tag = tagDefinition.isControlTag() ? new DefaultControlTag(ControlTagType.getTypeFromId(tagDefinition.getId()), objectType, objectId, clock.getUTCNow()) :
+                                new DescriptiveTag(tagDefinition.getId(), objectType, objectId, clock.getUTCNow());
 
-                // Have to fetch the history record ids to update the audit log
-                final List<Mapper<Long, Long>> historyRecordIds = tagSqlDao.getHistoryRecordIds(maxHistoryRecordId, context);
-                final Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
-                final List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap, context);
-                tagSqlDao.insertAuditFromTransaction(entityAudits, context);
+                // Create the tag
+                entitySqlDaoWrapperFactory.become(TagSqlDao.class).create(tag, context);
 
                 // Post an event to the Bus
                 final TagInternalEvent tagEvent;
@@ -143,79 +138,45 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements
 
     @Override
     public void deleteTag(final UUID objectId, final ObjectType objectType, final UUID tagDefinitionId, final InternalCallContext context) throws TagApiException {
-        try {
-            tagSqlDao.inTransaction(new Transaction<Void, TagSqlDao>() {
-                @Override
-                public Void inTransaction(final TagSqlDao transTagSqlDao, final TransactionStatus status) throws Exception {
-
-                    final TagDefinition tagDefinition = getTagDefinitionFromTransaction(tagDefinitionId, context);
-                    final Tag tag = tagSqlDao.findTag(tagDefinitionId.toString(), objectId.toString(), objectType, context);
-                    if (tag == null) {
-                        throw new TagApiException(ErrorCode.TAG_DOES_NOT_EXIST, tagDefinition.getName());
-                    }
-
-                    final List<Tag> tagList = Arrays.asList(tag);
-
-                    // Before the deletion, gather the tag ids for this object id
-                    final List<Mapper<UUID, Long>> recordIds = tagSqlDao.getRecordIds(objectId.toString(), objectType, context);
-                    final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds, objectType);
-
-                    // Delete the tag
-                    tagSqlDao.deleteFromTransaction(objectId.toString(), objectType, tagList, context);
-
-                    // Update the history table
-                    final List<EntityHistory<Tag>> entityHistories = convertToHistory(tagList, recordIdMap, ChangeType.DELETE);
-                    final Long maxHistoryRecordId = tagSqlDao.getMaxHistoryRecordId(context);
-                    tagSqlDao.addHistoryFromTransaction(objectId.toString(), objectType, entityHistories, context);
 
-                    // Have to fetch the history record ids to update the audit log
-                    final List<Mapper<Long, Long>> historyRecordIds = tagSqlDao.getHistoryRecordIds(maxHistoryRecordId, context);
-                    final Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
-                    final List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap, context);
-                    tagSqlDao.insertAuditFromTransaction(entityAudits, context);
+        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
 
-                    // Post an event to the Bus
-                    final TagInternalEvent tagEvent;
-                    if (tagDefinition.isControlTag()) {
-                        tagEvent = tagEventBuilder.newControlTagDeletionEvent(tag.getId(), objectId, objectType, tagDefinition, context);
-                    } else {
-                        tagEvent = tagEventBuilder.newUserTagDeletionEvent(tag.getId(), objectId, objectType, tagDefinition, context);
-                    }
-                    try {
-                        bus.postFromTransaction(tagEvent, tagSqlDao, context);
-                    } catch (InternalBus.EventBusException e) {
-                        log.warn("Failed to post tag deletion event for tag " + tag.getId().toString(), e);
+            @Override
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+
+                final TagDefinition tagDefinition = getTagDefinitionFromTransaction(tagDefinitionId, entitySqlDaoWrapperFactory, context);
+                final TagSqlDao transactional = entitySqlDaoWrapperFactory.become(TagSqlDao.class);
+                final List<Tag> tags = transactional.getTagsForObject(objectId, objectType, context);
+                Tag tag = null;
+                for (Tag cur : tags) {
+                    if (cur.getTagDefinitionId().equals(tagDefinitionId)) {
+                        tag = cur;
+                        break;
                     }
-                    return null;
                 }
-            });
-        } catch (TransactionFailedException exception) {
-
-            if (exception.getCause() instanceof TagDefinitionApiException) {
-                throw (TagApiException) exception.getCause();
-            } else {
-                throw exception;
-            }
-        }
-    }
+                if (tag == null) {
+                    throw new TagApiException(ErrorCode.TAG_DOES_NOT_EXIST, tagDefinition.getName());
+                }
 
-    @Override
-    protected TableName getTableName(final InternalTenantContext context) {
-        return TableName.TAG_HISTORY;
-    }
+                // Delete the tag
+                transactional.deleteById(tag.getId(), context);
 
-    @Override
-    protected UpdatableEntityCollectionSqlDao<Tag> transmogrifyDao(final Transmogrifier transactionalDao, final InternalTenantContext context) {
-        return transactionalDao.become(TagSqlDao.class);
-    }
-
-    @Override
-    protected UpdatableEntityCollectionSqlDao<Tag> getSqlDao(final InternalTenantContext context) {
-        return tagSqlDao;
-    }
+                // Post an event to the Bus
+                final TagInternalEvent tagEvent;
+                if (tagDefinition.isControlTag()) {
+                    tagEvent = tagEventBuilder.newControlTagDeletionEvent(tag.getId(), objectId, objectType, tagDefinition, context);
+                } else {
+                    tagEvent = tagEventBuilder.newUserTagDeletionEvent(tag.getId(), objectId, objectType, tagDefinition, context);
+                }
+                try {
+                    // TODO ETX
+                    bus.postFromTransaction(tagEvent, tagSqlDao, context);
+                } catch (InternalBus.EventBusException e) {
+                    log.warn("Failed to post tag deletion event for tag " + tag.getId().toString(), e);
+                }
+                return null;
+            }
+        });
 
-    @Override
-    protected String getKey(final Tag entity, final InternalTenantContext context) {
-        return entity.getId().toString();
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
index ccca5ce..bb82f20 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
@@ -16,17 +16,23 @@
 
 package com.ning.billing.util.tag.dao;
 
+import java.util.Map;
 import java.util.UUID;
 
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.dao.AuditedCollectionDao;
 import com.ning.billing.util.tag.Tag;
 
-public interface TagDao extends AuditedCollectionDao<Tag> {
+public interface TagDao {
 
     void insertTag(UUID objectId, ObjectType objectType, UUID tagDefinition, InternalCallContext context) throws TagApiException;
 
     void deleteTag(UUID objectId, ObjectType objectType, UUID tagDefinition, InternalCallContext context) throws TagApiException;
+
+    Tag getTagById(UUID tagId, InternalTenantContext context);
+
+    Map<String,Tag> getTags(UUID objectId, ObjectType objectType, InternalTenantContext internalTenantContext);
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
index ba23fdd..69db67b 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
@@ -53,7 +53,6 @@ import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
-@RegisterArgumentFactory({UUIDArgumentFactory.class, DateTimeArgumentFactory.class, EnumArgumentFactory.class})
 @EntitySqlDaoStringTemplate
 @RegisterMapper(TagDefinitionSqlDao.TagDefinitionMapper.class)
 public interface TagDefinitionSqlDao extends EntitySqlDao<TagDefinition> {
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagHistoryBinder.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagHistoryBinder.java
index 4ef9100..0f91570 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagHistoryBinder.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagHistoryBinder.java
@@ -41,7 +41,7 @@ public @interface TagHistoryBinder {
                 @Override
                 public void bind(final SQLStatement<?> q, final TagHistoryBinder bind, final EntityHistory<Tag> tagHistory) {
 
-                    q.bind("recordId", tagHistory.getValue());
+                    //q.bind("recordId", tagHistory.getValue());
                     q.bind("changeType", tagHistory.getChangeType().toString());
                     q.bind("id", tagHistory.getId().toString());
                     q.bind("tagDefinitionId", tagHistory.getEntity().getTagDefinitionId().toString());
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
index 6ce665b..52dc7b9 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
@@ -24,6 +24,7 @@ import org.joda.time.DateTime;
 import org.skife.jdbi.v2.StatementContext;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
+import com.ning.billing.ObjectType;
 import com.ning.billing.util.dao.MapperBase;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.DefaultControlTag;
@@ -44,12 +45,14 @@ public class TagMapper extends MapperBase implements ResultSetMapper<Tag> {
             }
         }
 
+        final ObjectType objectType = ObjectType.valueOf(result.getString("object_type"));
+        final UUID objectId = getUUID(result, "object_id");
         final UUID id = getUUID(result, "id");
         final DateTime createdDate = getDateTime(result, "created_date");
         if (thisTagType == null) {
-            return new DescriptiveTag(id, createdDate, tagDefinitionId);
+            return new DescriptiveTag(id, tagDefinitionId, objectType, objectId, createdDate);
         } else {
-            return new DefaultControlTag(id, createdDate, thisTagType);
+            return new DefaultControlTag(id, thisTagType, objectType, objectId, createdDate);
         }
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagSqlDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagSqlDao.java
index 3fda8fc..9fc3659 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagSqlDao.java
@@ -18,8 +18,11 @@ package com.ning.billing.util.tag.dao;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.UUID;
 
 import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.BindBean;
 import org.skife.jdbi.v2.sqlobject.SqlBatch;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
@@ -34,57 +37,19 @@ import com.ning.billing.util.callcontext.InternalTenantContextBinder;
 import com.ning.billing.util.dao.EntityHistory;
 import com.ning.billing.util.dao.ObjectTypeBinder;
 import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.TagDefinition;
 
 @EntitySqlDaoStringTemplate
 @RegisterMapper(TagMapper.class)
-public interface TagSqlDao extends UpdatableEntityCollectionSqlDao<Tag>, Transactional<TagSqlDao>, Transmogrifier {
+public interface TagSqlDao extends EntitySqlDao<Tag> {
 
-    @Override
-    @SqlBatch(transactional = false)
-    public void insertFromTransaction(@Bind("objectId") final String objectId,
-                                      @ObjectTypeBinder final ObjectType objectType,
-                                      @TagBinder final Collection<Tag> tags,
-                                      @InternalTenantContextBinder final InternalCallContext context);
-
-    @Override
-    @SqlBatch(transactional = false)
-    public void updateFromTransaction(@Bind("objectId") final String objectId,
-                                      @ObjectTypeBinder final ObjectType objectType,
-                                      @TagBinder final Collection<Tag> tags,
-                                      @InternalTenantContextBinder final InternalCallContext context);
-
-    @Override
-    @SqlBatch(transactional = false)
-    public void deleteFromTransaction(@Bind("objectId") final String objectId,
-                                      @ObjectTypeBinder final ObjectType objectType,
-                                      @TagBinder final Collection<Tag> tags,
-                                      @InternalTenantContextBinder final InternalCallContext context);
-
-    @Override
-    @SqlBatch(transactional = false)
-    public void addHistoryFromTransaction(@Bind("objectId") final String objectId,
-                                          @ObjectTypeBinder final ObjectType objectType,
-                                          @TagHistoryBinder final List<EntityHistory<Tag>> histories,
-                                          @InternalTenantContextBinder final InternalCallContext context);
-
-    @SqlUpdate
-    public void addTagFromTransaction(@Bind("id") final String tagId,
-                                      @Bind("tagDefinitionId") final String tagDefinitionId,
-                                      @Bind("objectId") final String objectId,
-                                      @ObjectTypeBinder final ObjectType objectType,
-                                      @InternalTenantContextBinder final InternalCallContext context);
 
     @SqlUpdate
-    public void removeTagFromTransaction(@Bind("tagDefinitionId") final String tagDefinitionId,
-                                         @Bind("objectId") final String objectId,
-                                         @ObjectTypeBinder final ObjectType objectType,
-                                         @InternalTenantContextBinder final InternalCallContext context);
+    void deleteById(@Bind("id") UUID id, @BindBean InternalCallContext context);
 
     @SqlQuery
-    public Tag findTag(@Bind("tagDefinitionId") final String tagDefinitionId,
-                       @Bind("objectId") final String objectId,
-                       @ObjectTypeBinder final ObjectType objectType,
-                       @InternalTenantContextBinder final InternalTenantContext context);
+    List<Tag> getTagsForObject(@Bind("objectId") UUID objectId, @Bind("objectType") ObjectType objectType, @BindBean InternalTenantContext internalTenantContext);
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/DefaultControlTag.java b/util/src/main/java/com/ning/billing/util/tag/DefaultControlTag.java
index f18844f..ec92f07 100644
--- a/util/src/main/java/com/ning/billing/util/tag/DefaultControlTag.java
+++ b/util/src/main/java/com/ning/billing/util/tag/DefaultControlTag.java
@@ -18,23 +18,22 @@ package com.ning.billing.util.tag;
 
 import java.util.UUID;
 
-import javax.annotation.Nullable;
-
 import org.joda.time.DateTime;
 
+import com.ning.billing.ObjectType;
+
 public class DefaultControlTag extends DescriptiveTag implements ControlTag {
 
     private final ControlTagType controlTagType;
 
     // use to create new objects
-    public DefaultControlTag(final ControlTagType controlTagType) {
-        super(controlTagType.getId());
-        this.controlTagType = controlTagType;
+    public DefaultControlTag(final ControlTagType controlTagType, ObjectType objectType, UUID objectId, DateTime createdDate) {
+        this(UUID.randomUUID(), controlTagType, objectType, objectId, createdDate);
     }
 
     // use to hydrate objects when loaded from the persistence layer
-    public DefaultControlTag(final UUID id, @Nullable final DateTime createdDate, final ControlTagType controlTagType) {
-        super(id, createdDate, controlTagType.getId());
+    public DefaultControlTag(final UUID id, final ControlTagType controlTagType, ObjectType objectType, UUID objectId, DateTime createdDate) {
+        super(id, controlTagType.getId(), objectType, objectId, createdDate);
         this.controlTagType = controlTagType;
     }
 
diff --git a/util/src/main/java/com/ning/billing/util/tag/DescriptiveTag.java b/util/src/main/java/com/ning/billing/util/tag/DescriptiveTag.java
index e916d3e..acf4fbb 100644
--- a/util/src/main/java/com/ning/billing/util/tag/DescriptiveTag.java
+++ b/util/src/main/java/com/ning/billing/util/tag/DescriptiveTag.java
@@ -22,22 +22,29 @@ import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
 
+import com.ning.billing.ObjectType;
 import com.ning.billing.util.entity.EntityBase;
 
 public class DescriptiveTag extends EntityBase implements Tag {
 
     private final UUID tagDefinitionId;
+    private final UUID objectId;
+    private final ObjectType objectType;
 
     // use to hydrate objects from the persistence layer
-    public DescriptiveTag(final UUID id, @Nullable final DateTime createdDate, final UUID tagDefinitionId) {
+    public DescriptiveTag(final UUID id, final UUID tagDefinitionId, final ObjectType objectType, final UUID objectId, final DateTime createdDate) {
         super(id, createdDate, createdDate);
         this.tagDefinitionId = tagDefinitionId;
+        this.objectType = objectType;
+        this.objectId = objectId;
     }
 
     // use to create new objects
-    public DescriptiveTag(final UUID tagDefinitionId) {
-        super();
+    public DescriptiveTag(final UUID tagDefinitionId, final ObjectType objectType, final UUID objectId, final DateTime createdDate) {
+        super(UUID.randomUUID(), createdDate, createdDate);
         this.tagDefinitionId = tagDefinitionId;
+        this.objectType = objectType;
+        this.objectId = objectId;
     }
 
     @Override
@@ -46,6 +53,16 @@ public class DescriptiveTag extends EntityBase implements Tag {
     }
 
     @Override
+    public ObjectType getObjectType() {
+        return objectType;
+    }
+
+    @Override
+    public UUID getObjectId() {
+        return objectId;
+    }
+
+    @Override
     public String toString() {
         return "DescriptiveTag [tagDefinitionId=" + tagDefinitionId + ", id=" + id + "]";
     }
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index 06002da..11af132 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -85,6 +85,8 @@ CREATE TABLE tags (
     object_type varchar(30) NOT NULL,
     created_by varchar(50) NOT NULL,
     created_date datetime NOT NULL,
+    updated_by varchar(50) NOT NULL,
+    updated_date datetime NOT NULL,
     account_record_id int(11) unsigned default null,
     tenant_record_id int(11) unsigned default null,
     PRIMARY KEY(record_id)
@@ -96,20 +98,22 @@ CREATE INDEX tags_tenant_account_record_id ON tags(tenant_record_id, account_rec
 
 DROP TABLE IF EXISTS tag_history;
 CREATE TABLE tag_history (
-    history_record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
-    record_id int(11) unsigned NOT NULL,
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     id char(36) NOT NULL,
+    target_record_id int(11) unsigned NOT NULL,
     object_id char(36) NOT NULL,
     object_type varchar(30) NOT NULL,
     tag_definition_id char(36) NOT NULL,
-    updated_by varchar(50) NOT NULL,
-    date datetime NOT NULL,
     change_type char(6) NOT NULL,
+    created_date datetime NOT NULL,
+    created_by varchar(50) NOT NULL,
+    updated_date datetime NOT NULL,
+    updated_by varchar(50) NOT NULL,
     account_record_id int(11) unsigned default null,
     tenant_record_id int(11) unsigned default null,
-    PRIMARY KEY(history_record_id)
+    PRIMARY KEY(record_id)
 ) ENGINE = innodb;
-CREATE INDEX tag_history_record_id ON tag_history(record_id);
+CREATE INDEX tag_history_target_record_id ON tag_history(target_record_id);
 CREATE INDEX tag_history_by_object ON tags(object_id);
 CREATE INDEX tag_history_tenant_account_record_id ON tag_history(tenant_record_id, account_record_id);
 
diff --git a/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
index d3752d4..bbfc58d 100644
--- a/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
@@ -169,11 +169,11 @@ where <recordIdField("t.")> = :recordId
 >>
 
 
-getHistoryRecordIdsForTable(tableName) ::= <<
+getHistoryRecordIdsForTable(historyTableName) ::= <<
 select
-  <recordIdField("t.")> record_id
-from <tableName> t
-where <idField("t.")> = :id
+  <recordIdField("t.")>
+from <historyTableName> t
+where <targetRecordIdField("t.")> = :targetRecordId
 <AND_CHECK_TENANT("t.")>
 ;
 >>
@@ -269,7 +269,7 @@ from <auditTableName()> t
 where t.target_record_id = :targetRecordId
 and t.table_name = :tableName
 <AND_CHECK_TENANT("t.")>
-order by change_date ASC
+order by created_date ASC
 ;
 >>
 
diff --git a/util/src/main/resources/com/ning/billing/util/tag/dao/TagSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/tag/dao/TagSqlDao.sql.stg
index 390f994..3dd5e0f 100644
--- a/util/src/main/resources/com/ning/billing/util/tag/dao/TagSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/tag/dao/TagSqlDao.sql.stg
@@ -8,16 +8,37 @@ tableFields(prefix) ::= <<
 , <prefix>object_type
 , <prefix>created_by
 , <prefix>created_date
+, <prefix>updated_by
+, <prefix>updated_date
+>>
+
+tableValues() ::= <<
+  :tagDefinitionId
+, :objectId
+, :objectType
+, :createdBy
+, :createdDate
+, :updatedBy
+, :updatedDate
 >>
 
 historyTableName() ::= "tag_history"
 
-deleteFromTransaction() ::= <<
-    DELETE FROM tags
-    WHERE tag_definition_id = :tagDefinitionId
-        AND object_id = :objectId AND object_type = :objectType
-    <AND_CHECK_TENANT()>
-    ;
+deleteById() ::= <<
+delete from <tableName()>
+where id = :id
+<AND_CHECK_TENANT()>
+;
+>>
+
+getTagsForObject() ::= <<
+select
+<allTableFields()>
+from <tableName()>
+where
+object_id = :objectId AND object_type = :objectType
+<AND_CHECK_TENANT()>
+;
 >>
 
 findTag() ::= <<
diff --git a/util/src/test/java/com/ning/billing/dbi/DBIProvider.java b/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
index 4855d78..6c827f7 100644
--- a/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
+++ b/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
@@ -16,10 +16,17 @@
 
 package com.ning.billing.dbi;
 
+import java.util.concurrent.TimeUnit;
+
 import org.skife.jdbi.v2.DBI;
 import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterArgumentFactory;
 import org.skife.jdbi.v2.tweak.transactions.SerializableTransactionRunner;
 
+import com.ning.billing.util.dao.DateTimeArgumentFactory;
+import com.ning.billing.util.dao.EnumArgumentFactory;
+import com.ning.billing.util.dao.UUIDArgumentFactory;
+
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.jolbox.bonecp.BoneCPConfig;
@@ -27,29 +34,40 @@ import com.jolbox.bonecp.BoneCPDataSource;
 
 public class DBIProvider implements Provider<IDBI> {
 
-    private final DbiConfig config;
+    private final BoneCPConfig dbConfig;
 
     @Inject
     public DBIProvider(final DbiConfig config) {
-        this.config = config;
+        this(config.getJdbcUrl(), config.getUsername(), config.getPassword());
     }
 
-    @Override
-    public IDBI get() {
+    public DBIProvider(final String dbiString, final String userName, final String pwd) {
+        this.dbConfig = createConfig(dbiString, userName, pwd);
+    }
+
+    BoneCPConfig createConfig(final String dbiString, final String userName, final String pwd) {
         final BoneCPConfig dbConfig = new BoneCPConfig();
-        dbConfig.setJdbcUrl(config.getJdbcUrl());
-        dbConfig.setUsername(config.getUsername());
-        dbConfig.setPassword(config.getPassword());
-        dbConfig.setMinConnectionsPerPartition(config.getMinIdle());
-        dbConfig.setMaxConnectionsPerPartition(config.getMaxActive());
-        dbConfig.setConnectionTimeout(config.getConnectionTimeout().getPeriod(), config.getConnectionTimeout().getUnit());
+        dbConfig.setJdbcUrl(dbiString);
+        dbConfig.setUsername(userName);
+        dbConfig.setPassword(pwd);
+        dbConfig.setMinConnectionsPerPartition(1);
+        dbConfig.setMaxConnectionsPerPartition(30);
+        dbConfig.setConnectionTimeout(10, TimeUnit.SECONDS);
         dbConfig.setPartitionCount(1);
         dbConfig.setDefaultTransactionIsolation("REPEATABLE_READ");
         dbConfig.setDisableJMX(false);
         dbConfig.setLazyInit(true);
+        return dbConfig;
+    }
 
+    @Override
+    public IDBI get() {
         final BoneCPDataSource ds = new BoneCPDataSource(dbConfig);
         final DBI dbi = new DBI(ds);
+        dbi.registerArgumentFactory(new UUIDArgumentFactory());
+        dbi.registerArgumentFactory(new DateTimeArgumentFactory());
+        dbi.registerArgumentFactory(new EnumArgumentFactory());
+
         // Restart transactions in case of deadlocks
         dbi.setTransactionHandler(new SerializableTransactionRunner());
         //final SQLLog log = new Log4JLog();
diff --git a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
index 8a07862..b5105a9 100644
--- a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
+++ b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
@@ -175,9 +175,14 @@ public class MysqlTestingHelper {
         }
     }
 
-    public IDBI getDBI() {
-        final String dbiString = getJdbcConnectionString() + "?createDatabaseIfNotExist=true&allowMultiQueries=true";
-        return new DBI(dbiString, USERNAME, PASSWORD);
+    private IDBI dbiInstance = null;
+
+    public synchronized IDBI getDBI() {
+        if (dbiInstance == null) {
+            final String dbiString = getJdbcConnectionString() + "?createDatabaseIfNotExist=true&allowMultiQueries=true";
+            dbiInstance = new DBIProvider(dbiString, USERNAME, PASSWORD).get();
+        }
+        return dbiInstance;
     }
 
     public String getJdbcConnectionString() {
diff --git a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
index 1c4bc59..799d91b 100644
--- a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
+++ b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
@@ -116,7 +116,7 @@ public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
         // Create a tag
         final UUID objectId = UUID.randomUUID();
         tagDao.insertTag(objectId, ObjectType.ACCOUNT, tagDefinition.getId(), internalCallContext);
-        final Map<String, Tag> tags = tagDao.loadEntities(objectId, ObjectType.ACCOUNT, internalCallContext);
+        final Map<String, Tag> tags = tagDao.getTags(objectId, ObjectType.ACCOUNT, internalCallContext);
         Assert.assertEquals(tags.size(), 1);
         final Tag tag = tags.values().iterator().next();
         Assert.assertEquals(tag.getTagDefinitionId(), tagDefinition.getId());
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
index db56f4b..ec103f2 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
@@ -37,26 +37,6 @@ public class MockTagDao implements TagDao {
 
     private final Map<UUID, List<Tag>> tagStore = new HashMap<UUID, List<Tag>>();
 
-    @Override
-    public void saveEntitiesFromTransaction(final Transmogrifier dao, final UUID objectId, final ObjectType objectType,
-                                            final List<Tag> tags, final InternalCallContext context) {
-        tagStore.put(objectId, tags);
-    }
-
-    @Override
-    public void saveEntities(final UUID objectId, final ObjectType objectType, final List<Tag> tags, final InternalCallContext context) {
-        tagStore.put(objectId, tags);
-    }
-
-    @Override
-    public Map<String, Tag> loadEntities(final UUID objectId, final ObjectType objectType, final InternalTenantContext context) {
-        return getMap(tagStore.get(objectId));
-    }
-
-    @Override
-    public Map<String, Tag> loadEntitiesFromTransaction(final Transmogrifier dao, final UUID objectId, final ObjectType objectType, final InternalTenantContext context) {
-        return getMap(tagStore.get(objectId));
-    }
 
     private Map<String, Tag> getMap(@Nullable final List<Tag> tags) {
         final Map<String, Tag> map = new HashMap<String, Tag>();
@@ -80,6 +60,16 @@ public class MockTagDao implements TagDao {
             }
 
             @Override
+            public ObjectType getObjectType() {
+                return objectType;
+            }
+
+            @Override
+            public UUID getObjectId() {
+                return objectId;
+            }
+
+            @Override
             public UUID getId() {
                 return id;
             }
@@ -116,4 +106,14 @@ public class MockTagDao implements TagDao {
             }
         }
     }
+
+    @Override
+    public Tag getTagById(final UUID tagId, final InternalTenantContext context) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, Tag> getTags(final UUID objectId, final ObjectType objectType, final InternalTenantContext internalTenantContext) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
index deaaf4f..054b065 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
@@ -168,7 +168,7 @@ public class TestAuditedTagDao extends UtilTestSuiteWithEmbeddedDB {
         tagDao.insertTag(objectId, objectType, createdTagDefinition.getId(), internalCallContext);
 
         // Make sure we can retrieve it via the DAO
-        final Map<String, Tag> foundTags = tagDao.loadEntities(objectId, objectType, internalCallContext);
+        final Map<String, Tag> foundTags = tagDao.getTags(objectId, objectType, internalCallContext);
         Assert.assertEquals(foundTags.keySet().size(), 1);
         Assert.assertEquals(foundTags.values().iterator().next().getTagDefinitionId(), createdTagDefinition.getId());
 
@@ -188,7 +188,7 @@ public class TestAuditedTagDao extends UtilTestSuiteWithEmbeddedDB {
         tagDao.deleteTag(objectId, objectType, createdTagDefinition.getId(), internalCallContext);
 
         // Make sure the tag is deleted
-        Assert.assertEquals(tagDao.loadEntities(objectId, objectType, internalCallContext).keySet().size(), 0);
+        Assert.assertEquals(tagDao.getTags(objectId, objectType, internalCallContext).keySet().size(), 0);
 
         // Verify we caught an event on the bus
         Assert.assertEquals(eventsListener.getEvents().size(), 3);
diff --git a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
index 3cb089b..ddf9bd8 100644
--- a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
+++ b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
@@ -17,14 +17,9 @@
 package com.ning.billing.util.tag;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-import org.joda.time.Seconds;
-import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,8 +33,8 @@ import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
-import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.tag.dao.TagDao;
 import com.ning.billing.util.tag.dao.TagDefinitionDao;
 
@@ -73,7 +68,7 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
     @Inject
     private InternalBus bus;
 
-    private TagDefinition testTag;
+    private TagDefinition testTagDefinition;
 
     private final Logger log = LoggerFactory.getLogger(TestTagStore.class);
 
@@ -83,7 +78,7 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
             bus.start();
 
             tagDefinitionDao.create("tag1", "First tag", internalCallContext);
-            testTag = tagDefinitionDao.create("testTag", "Second tag", internalCallContext);
+            testTagDefinition = tagDefinitionDao.create("testTagDefinition", "Second tag", internalCallContext);
         } catch (Throwable t) {
             log.error("Failed to start tag store tests", t);
             fail(t.toString());
@@ -96,129 +91,31 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testTagCreationAndRetrieval() {
+    public void testTagCreationAndRetrieval() throws TagApiException {
         final UUID accountId = UUID.randomUUID();
+        final Tag tag = new DescriptiveTag(testTagDefinition.getId(), UUID.randomUUID(), ObjectType.ACCOUNT, accountId, clock.getUTCNow());
 
-        final TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
-        final Tag tag = new DescriptiveTag(testTag.getId());
-        tagStore.add(tag);
-
-        tagDao.saveEntities(accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), internalCallContext);
+        tagDao.insertTag(accountId, ObjectType.ACCOUNT, tag.getTagDefinitionId(), internalCallContext);
 
-        final Map<String, Tag> savedTags = tagDao.loadEntities(accountId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(savedTags.size(), 1);
-
-        final Tag savedTag = savedTags.get(tag.getId().toString());
+        final Tag savedTag = tagDao.getTagById(tag.getId(), internalCallContext);
         assertEquals(savedTag.getTagDefinitionId(), tag.getTagDefinitionId());
         assertEquals(savedTag.getId(), tag.getId());
     }
 
-    @Test(groups = "slow")
-    public void testControlTagCreation() {
-        final UUID accountId = UUID.randomUUID();
-        final TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
-
-        final ControlTag tag = new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF);
-        tagStore.add(tag);
-        assertEquals(tagStore.generateInvoice(), false);
-
-        final List<Tag> tagList = tagStore.getEntityList();
-        tagDao.saveEntities(accountId, ObjectType.ACCOUNT, tagList, internalCallContext);
-
-        tagStore.clear();
-        assertEquals(tagStore.getEntityList().size(), 0);
-
-        final Map<String, Tag> tagMap = tagDao.loadEntities(accountId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(tagMap.size(), 1);
-
-        assertEquals(tagMap.values().iterator().next().getTagDefinitionId(), ControlTagType.AUTO_INVOICING_OFF.getId());
-    }
 
     @Test(groups = "slow")
-    public void testDescriptiveTagCreation() {
+    public void testControlTagCreation() throws TagApiException {
         final UUID accountId = UUID.randomUUID();
-        final TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
 
-        final String definitionName = "SomeTestTag";
-        TagDefinition tagDefinition = null;
-        try {
-            tagDefinition = tagDefinitionDao.create(definitionName, "Test tag for some test purpose", internalCallContext);
-        } catch (TagDefinitionApiException e) {
-            fail("Tag definition creation failed.", e);
-        }
+        final ControlTag tag = new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF, ObjectType.ACCOUNT, accountId, clock.getUTCNow());
 
-        final DescriptiveTag tag = new DescriptiveTag(tagDefinition.getId());
-        tagStore.add(tag);
-        assertEquals(tagStore.generateInvoice(), true);
-
-        tagDao.saveEntities(accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), internalCallContext);
-
-        tagStore.clear();
-        assertEquals(tagStore.getEntityList().size(), 0);
-
-        final Map<String, Tag> tagMap = tagDao.loadEntities(accountId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(tagMap.size(), 1);
-
-        assertEquals(tagMap.values().iterator().next().getTagDefinitionId(), tagDefinition.getId());
-    }
-
-    @Test(groups = "slow")
-    public void testMixedTagCreation() {
-        final UUID accountId = UUID.randomUUID();
-        final TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
-
-        final String definitionName = "MixedTagTest";
-        TagDefinition tagDefinition = null;
-        try {
-            tagDefinition = tagDefinitionDao.create(definitionName, "Test tag for some test purpose", internalCallContext);
-        } catch (TagDefinitionApiException e) {
-            fail("Tag definition creation failed.", e);
-        }
-
-        final DescriptiveTag descriptiveTag = new DescriptiveTag(tagDefinition.getId());
-        tagStore.add(descriptiveTag);
-        assertEquals(tagStore.generateInvoice(), true);
-
-        final ControlTag controlTag = new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF);
-        tagStore.add(controlTag);
-        assertEquals(tagStore.generateInvoice(), false);
-
-        tagDao.saveEntities(accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), internalCallContext);
-
-        tagStore.clear();
-        assertEquals(tagStore.getEntityList().size(), 0);
-
-        final Map<String, Tag> tagMap = tagDao.loadEntities(accountId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(tagMap.size(), 2);
-
-        boolean found_AUTO_INVOICING_OFF_tag = false;
-        for (Tag cur : tagMap.values()) {
-            if (cur.getTagDefinitionId().equals(ControlTagType.AUTO_INVOICING_OFF.getId())) {
-                found_AUTO_INVOICING_OFF_tag = true;
-                break;
-            }
-        }
-        assertEquals(found_AUTO_INVOICING_OFF_tag, true);
+        tagDao.insertTag(accountId, ObjectType.ACCOUNT, tag.getTagDefinitionId(), internalCallContext);
 
+        final Tag savedTag = tagDao.getTagById(tag.getId(), internalCallContext);
+        assertEquals(savedTag.getTagDefinitionId(), tag.getTagDefinitionId());
+        assertEquals(savedTag.getId(), tag.getId());
     }
 
-    @Test(groups = "slow")
-    public void testControlTags() {
-        final UUID accountId = UUID.randomUUID();
-        final TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
-        assertEquals(tagStore.generateInvoice(), true);
-        assertEquals(tagStore.processPayment(), true);
-
-        final ControlTag invoiceTag = new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF);
-        tagStore.add(invoiceTag);
-        assertEquals(tagStore.generateInvoice(), false);
-        assertEquals(tagStore.processPayment(), true);
-
-        final ControlTag paymentTag = new DefaultControlTag(ControlTagType.AUTO_PAY_OFF);
-        tagStore.add(paymentTag);
-        assertEquals(tagStore.generateInvoice(), false);
-        assertEquals(tagStore.processPayment(), false);
-    }
 
     @Test(groups = "slow", expectedExceptions = TagDefinitionApiException.class)
     public void testTagDefinitionCreationWithControlTagName() throws TagDefinitionApiException {
@@ -240,7 +137,7 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow", expectedExceptions = TagDefinitionApiException.class)
-    public void testTagDefinitionDeletionForDefinitionInUse() throws TagDefinitionApiException {
+    public void testTagDefinitionDeletionForDefinitionInUse() throws TagDefinitionApiException, TagApiException {
         final String definitionName = "TestTag12345";
         tagDefinitionDao.create(definitionName, "Some test tag", internalCallContext);
 
@@ -248,14 +145,8 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
         assertNotNull(tagDefinition);
 
         final UUID objectId = UUID.randomUUID();
-        final TagStore tagStore = new DefaultTagStore(objectId, ObjectType.ACCOUNT);
-        final Tag tag = new DescriptiveTag(tagDefinition.getId());
-        tagStore.add(tag);
-
-        tagDao.saveEntities(objectId, ObjectType.ACCOUNT, tagStore.getEntityList(), internalCallContext);
 
-        final Map<String, Tag> tagMap = tagDao.loadEntities(objectId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(tagMap.size(), 1);
+        tagDao.insertTag(tagDefinition.getId(), ObjectType.ACCOUNT, objectId, internalCallContext);
 
         tagDefinitionDao.deleteById(tagDefinition.getId(), internalCallContext);
     }
@@ -273,18 +164,10 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
         assertNotNull(tagDefinition);
 
         final UUID objectId = UUID.randomUUID();
-        final TagStore tagStore = new DefaultTagStore(objectId, ObjectType.ACCOUNT);
-        final Tag tag = new DescriptiveTag(tagDefinition.getId());
-        tagStore.add(tag);
 
-        tagDao.saveEntities(objectId, ObjectType.ACCOUNT, tagStore.getEntityList(), internalCallContext);
-
-        final Map<String, Tag> tagMap = tagDao.loadEntities(objectId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(tagMap.size(), 1);
+        tagDao.insertTag(tagDefinition.getId(), ObjectType.ACCOUNT, objectId, internalCallContext);
 
         tagDao.deleteTag(objectId, ObjectType.ACCOUNT, tagDefinition.getId(), internalCallContext);
-        final Map<String, Tag> tagMapAfterDeletion = tagDao.loadEntities(objectId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(tagMapAfterDeletion.size(), 0);
 
         try {
             tagDefinitionDao.deleteById(tagDefinition.getId(), internalCallContext);
@@ -298,113 +181,4 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
         final List<TagDefinition> definitionList = tagDefinitionDao.getTagDefinitions(internalCallContext);
         assertTrue(definitionList.size() >= ControlTagType.values().length);
     }
-
-    @Test
-    public void testTagInsertAudit() {
-        final UUID accountId = UUID.randomUUID();
-
-        final TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
-        final Tag tag = new DescriptiveTag(testTag.getId());
-        tagStore.add(tag);
-
-        tagDao.saveEntities(accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), internalCallContext);
-
-        final Map<String, Tag> savedTags = tagDao.loadEntities(accountId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(savedTags.size(), 1);
-
-        final Tag savedTag = savedTags.get(tag.getId().toString());
-        assertEquals(savedTag.getTagDefinitionId(), tag.getTagDefinitionId());
-        assertEquals(savedTag.getId(), tag.getId());
-
-        final Handle handle = dbi.open();
-        final String query = String.format("select * from audit_log a inner join tag_history th on a.record_id = th.history_record_id where a.table_name = 'tag_history' and th.id='%s' and a.change_type='INSERT'",
-                                           tag.getId().toString());
-        final List<Map<String, Object>> result = handle.select(query);
-        handle.close();
-
-        assertNotNull(result);
-        assertEquals(result.size(), 1);
-        assertEquals(result.get(0).get("change_type"), "INSERT");
-        assertNotNull(result.get(0).get("change_date"));
-        final DateTime changeDate = new DateTime(result.get(0).get("change_date"));
-        assertTrue(Seconds.secondsBetween(changeDate, internalCallContext.getCreatedDate()).getSeconds() < 2);
-        assertEquals(result.get(0).get("changed_by"), internalCallContext.getCreatedBy());
-    }
-
-    @Test
-    public void testTagDeleteAudit() {
-        final UUID accountId = UUID.randomUUID();
-
-        final TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
-        final Tag tag = new DescriptiveTag(testTag.getId());
-        tagStore.add(tag);
-
-        tagDao.saveEntities(accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), internalCallContext);
-
-        tagStore.remove(tag);
-        tagDao.saveEntities(accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), internalCallContext);
-
-        final Map<String, Tag> savedTags = tagDao.loadEntities(accountId, ObjectType.ACCOUNT, internalCallContext);
-        assertEquals(savedTags.size(), 0);
-
-        final Handle handle = dbi.open();
-        final String query = String.format("select * from audit_log a inner join tag_history th on a.record_id = th.history_record_id where a.table_name = 'tag_history' and th.id='%s' and a.change_type='DELETE'",
-                                           tag.getId().toString());
-        final List<Map<String, Object>> result = handle.select(query);
-        handle.close();
-
-        assertNotNull(result);
-        assertEquals(result.size(), 1);
-        assertNotNull(result.get(0).get("change_date"));
-        final DateTime changeDate = new DateTime(result.get(0).get("change_date"));
-        assertTrue(Seconds.secondsBetween(changeDate, internalCallContext.getUpdatedDate()).getSeconds() < 2);
-        assertEquals(result.get(0).get("changed_by"), internalCallContext.getCreatedBy());
-    }
-
-    @Test
-    public void testAddTag() throws TagApiException, TagDefinitionApiException {
-        final UUID objectId = UUID.randomUUID();
-        final ObjectType objectType = ObjectType.INVOICE;
-        final TagDefinition tagDefinition = tagDefinitionDao.create("test tag", "test", internalCallContext);
-        tagDao.insertTag(objectId, objectType, tagDefinition.getId(), internalCallContext);
-        final Map<String, Tag> savedTags = tagDao.loadEntities(objectId, objectType, internalCallContext);
-        assertEquals(savedTags.size(), 1);
-    }
-
-    @Test
-    public void testRemoveTag() throws TagApiException, TagDefinitionApiException {
-        final UUID objectId = UUID.randomUUID();
-        final ObjectType objectType = ObjectType.INVOICE;
-        final TagDefinition tagDefinition = tagDefinitionDao.create("test tag", "test", internalCallContext);
-        tagDao.insertTag(objectId, objectType, tagDefinition.getId(), internalCallContext);
-        Map<String, Tag> savedTags = tagDao.loadEntities(objectId, objectType, internalCallContext);
-        assertEquals(savedTags.size(), 1);
-
-        tagDao.deleteTag(objectId, objectType, tagDefinition.getId(), internalCallContext);
-        savedTags = tagDao.loadEntities(objectId, objectType, internalCallContext);
-        assertEquals(savedTags.size(), 0);
-    }
-
-    @Test
-    public void testSetTags() {
-        final UUID objectId = UUID.randomUUID();
-        final ObjectType objectType = ObjectType.INVOICE;
-
-        final List<Tag> tags = new ArrayList<Tag>();
-        tags.add(new DescriptiveTag(UUID.randomUUID()));
-        tags.add(new DescriptiveTag(UUID.randomUUID()));
-        tags.add(new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF));
-        tagDao.saveEntities(objectId, objectType, tags, internalCallContext);
-
-        Map<String, Tag> savedTags = tagDao.loadEntities(objectId, objectType, internalCallContext);
-        assertEquals(savedTags.size(), 3);
-
-        tags.remove(1);
-        assertEquals(tags.size(), 2);
-
-        tagDao.saveEntities(objectId, objectType, tags, internalCallContext);
-
-        savedTags = tagDao.loadEntities(objectId, objectType, internalCallContext);
-        assertEquals(savedTags.size(), 2);
-    }
 }