killbill-aplcache

Merge branch 'audit-rework' of github.com:killbill/killbill

11/8/2012 6:56:10 PM

Changes

util/src/main/resources/com/ning/billing/util/dao/AuditSqlDao.sql.stg 29(+0 -29)

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/callcontext/InternalCallContext.java b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContext.java
index 9f6da10..e79e5ca 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContext.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContext.java
@@ -28,7 +28,8 @@ import org.joda.time.DateTime;
 public class InternalCallContext extends InternalTenantContext {
 
     private final UUID userToken;
-    private final String userName;
+    private final String createdBy;
+    private final String updatedBy;
     private final CallOrigin callOrigin;
     private final UserType userType;
     private final String reasonCode;
@@ -41,7 +42,8 @@ public class InternalCallContext extends InternalTenantContext {
                                final DateTime createdDate, final DateTime updatedDate) {
         super(tenantRecordId, accountRecordId);
         this.userToken = userToken;
-        this.userName = userName;
+        this.createdBy = userName;
+        this.updatedBy = userName;
         this.callOrigin = callOrigin;
         this.userType = userType;
         this.reasonCode = reasonCode;
@@ -61,15 +63,19 @@ public class InternalCallContext extends InternalTenantContext {
     // Unfortunately not true as some APIs ae hidden in object-- e.g OverdueStateApplicator is doing subscription.cancelWithPolicy(polciy, context);
     //
     public CallContext toCallContext() {
-        return new DefaultCallContext(null, userName, callOrigin, userType, reasonCode, comment, userToken, createdDate, updatedDate);
+        return new DefaultCallContext(null, createdBy, callOrigin, userType, reasonCode, comment, userToken, createdDate, updatedDate);
     }
 
     public UUID getUserToken() {
         return userToken;
     }
 
-    public String getUserName() {
-        return userName;
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    public String getUpdatedBy() {
+        return updatedBy;
     }
 
     public CallOrigin getCallOrigin() {
@@ -101,7 +107,8 @@ public class InternalCallContext extends InternalTenantContext {
         final StringBuilder sb = new StringBuilder();
         sb.append("InternalCallContext");
         sb.append("{userToken=").append(userToken);
-        sb.append(", userName='").append(userName).append('\'');
+        sb.append(", createdBy='").append(createdBy).append('\'');
+        sb.append(", updatedBy='").append(updatedBy).append('\'');
         sb.append(", callOrigin=").append(callOrigin);
         sb.append(", userType=").append(userType);
         sb.append(", reasonCode='").append(reasonCode).append('\'');
@@ -132,16 +139,19 @@ public class InternalCallContext extends InternalTenantContext {
         if (comment != null ? !comment.equals(that.comment) : that.comment != null) {
             return false;
         }
+        if (createdBy != null ? !createdBy.equals(that.createdBy) : that.createdBy != null) {
+            return false;
+        }
         if (createdDate != null ? !createdDate.equals(that.createdDate) : that.createdDate != null) {
             return false;
         }
         if (reasonCode != null ? !reasonCode.equals(that.reasonCode) : that.reasonCode != null) {
             return false;
         }
-        if (updatedDate != null ? !updatedDate.equals(that.updatedDate) : that.updatedDate != null) {
+        if (updatedBy != null ? !updatedBy.equals(that.updatedBy) : that.updatedBy != null) {
             return false;
         }
-        if (userName != null ? !userName.equals(that.userName) : that.userName != null) {
+        if (updatedDate != null ? !updatedDate.equals(that.updatedDate) : that.updatedDate != null) {
             return false;
         }
         if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
@@ -158,7 +168,8 @@ public class InternalCallContext extends InternalTenantContext {
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
-        result = 31 * result + (userName != null ? userName.hashCode() : 0);
+        result = 31 * result + (createdBy != null ? createdBy.hashCode() : 0);
+        result = 31 * result + (updatedBy != null ? updatedBy.hashCode() : 0);
         result = 31 * result + (callOrigin != null ? callOrigin.hashCode() : 0);
         result = 31 * result + (userType != null ? userType.hashCode() : 0);
         result = 31 * result + (reasonCode != null ? reasonCode.hashCode() : 0);
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
index 97202bd..89fb15b 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
@@ -198,14 +198,14 @@ public class InternalCallContextFactory {
 
     // Used when we need to re-hydrate the context with the account_record_id (when creating the account)
     public InternalCallContext createInternalCallContext(final Long accountRecordId, final InternalCallContext context) {
-        return new InternalCallContext(context.getTenantRecordId(), accountRecordId, context.getUserToken(), context.getUserName(),
+        return new InternalCallContext(context.getTenantRecordId(), accountRecordId, context.getUserToken(), context.getCreatedBy(),
                                        context.getCallOrigin(), context.getUserType(), context.getReasonCode(), context.getComment(),
                                        context.getCreatedDate(), context.getUpdatedDate());
     }
 
     // Used when we need to re-hydrate the context with the tenant_record_id and account_record_id (when claiming bus events)
     public InternalCallContext createInternalCallContext(final Long tenantRecordId, final Long accountRecordId, final InternalCallContext context) {
-        return new InternalCallContext(tenantRecordId, accountRecordId, context.getUserToken(), context.getUserName(),
+        return new InternalCallContext(tenantRecordId, accountRecordId, context.getUserToken(), context.getCreatedBy(),
                                        context.getCallOrigin(), context.getUserType(), context.getReasonCode(), context.getComment(),
                                        context.getCreatedDate(), context.getUpdatedDate());
     }
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/InternalTenantContextBinder.java b/util/src/main/java/com/ning/billing/util/callcontext/InternalTenantContextBinder.java
index 0349be5..499e907 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/InternalTenantContextBinder.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/InternalTenantContextBinder.java
@@ -57,7 +57,7 @@ public @interface InternalTenantContextBinder {
 
                     if (context instanceof InternalCallContext) {
                         final InternalCallContext callContext = (InternalCallContext) context;
-                        q.bind("userName", callContext.getUserName());
+                        q.bind("userName", callContext.getCreatedBy());
                         if (callContext.getCreatedDate() == null) {
                             q.bindNull("createdDate", Types.DATE);
                         } else {
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldHistoryBinder.java b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldHistoryBinder.java
index 506017a..48b53dd 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldHistoryBinder.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldHistoryBinder.java
@@ -40,8 +40,8 @@ public @interface CustomFieldHistoryBinder {
             return new Binder<CustomFieldHistoryBinder, EntityHistory<CustomField>>() {
                 @Override
                 public void bind(final SQLStatement<?> q, final CustomFieldHistoryBinder bind, final EntityHistory<CustomField> customFieldHistory) {
-                    q.bind("recordId", customFieldHistory.getValue());
-                    q.bind("changeType", customFieldHistory.getChangeType().toString());
+//                    q.bind("recordId", customFieldHistory.getValue());
+//                    q.bind("changeType", customFieldHistory.getChangeType().toString());
                     q.bind("id", customFieldHistory.getId().toString());
                     q.bind("fieldName", customFieldHistory.getEntity().getName());
                     q.bind("fieldValue", customFieldHistory.getEntity().getValue());
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 5ec8499..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
@@ -19,6 +19,7 @@ package com.ning.billing.util.dao;
 import java.util.List;
 
 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;
@@ -30,38 +31,40 @@ 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 {
 
     @SqlUpdate
-    public void insertAuditFromTransaction(@AuditBinder final EntityAudit audit,
-                                           @InternalTenantContextBinder final InternalCallContext context);
+    public void insertAuditFromTransaction(@BindBean final EntityAudit audit,
+                                           @BindBean final InternalCallContext context);
 
     @SqlBatch(transactional = false)
-    public void insertAuditFromTransaction(@AuditBinder final List<EntityAudit> audit,
-                                           @InternalTenantContextBinder final InternalCallContext context);
+    public void insertAuditFromTransaction(@BindBean final List<EntityAudit> audit,
+                                           @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/dao/DateTimeArgumentFactory.java b/util/src/main/java/com/ning/billing/util/dao/DateTimeArgumentFactory.java
new file mode 100644
index 0000000..1e0cfc6
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/DateTimeArgumentFactory.java
@@ -0,0 +1,68 @@
+/*
+ * 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
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.Argument;
+import org.skife.jdbi.v2.tweak.ArgumentFactory;
+
+public class DateTimeArgumentFactory implements ArgumentFactory<DateTime> {
+
+    @Override
+    public boolean accepts(final Class<?> expectedType, final Object value, final StatementContext ctx) {
+        return value instanceof DateTime;
+    }
+
+    @Override
+    public Argument build(final Class<?> expectedType, final DateTime value, final StatementContext ctx) {
+        return new DateTimeArgument(value);
+    }
+
+    public static class DateTimeArgument implements Argument {
+
+        private final DateTime value;
+
+        public DateTimeArgument(final DateTime value) {
+            this.value = value;
+        }
+
+        @Override
+        public void apply(final int position, final PreparedStatement statement, final StatementContext ctx) throws SQLException {
+            if (value != null) {
+                statement.setTimestamp(position, new Timestamp(value.toDate().getTime()));
+            } else {
+                statement.setNull(position, Types.TIMESTAMP);
+            }
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("DateTimeArgument");
+            sb.append("{value=").append(value);
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/EntityHistory.java b/util/src/main/java/com/ning/billing/util/dao/EntityHistory.java
index 9ee036b..505b742 100644
--- a/util/src/main/java/com/ning/billing/util/dao/EntityHistory.java
+++ b/util/src/main/java/com/ning/billing/util/dao/EntityHistory.java
@@ -18,11 +18,39 @@ package com.ning.billing.util.dao;
 
 import java.util.UUID;
 
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.tweak.Argument;
+
 import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.entity.Entity;
+import com.ning.billing.util.entity.EntityBase;
+
+public class EntityHistory<T extends Entity> extends EntityBase {
+
+    private final Long targetRecordId;
+    private final T entity;
+    private ChangeType changeType;
+
+    public EntityHistory(final UUID id, final T src, final Long targetRecordId, final ChangeType type, final DateTime createdDate) {
+        super(id, createdDate, createdDate);
+        this.changeType = type;
+        this.targetRecordId = targetRecordId;
+        this.entity = src;
+    }
+
+    public EntityHistory(final T src, final Long targetRecordId, final ChangeType type, final DateTime createdDate) {
+        this(UUID.randomUUID(), src, targetRecordId, type, createdDate);
+    }
+
+    public ChangeType getChangeType() {
+        return changeType;
+    }
+
+    public T getEntity() {
+        return entity;
+    }
 
-public class EntityHistory<T extends Entity> extends MappedEntity<T, UUID, Long> {
-    public EntityHistory(final UUID id, final Long recordId, final T entity, final ChangeType changeType) {
-        super(new Mapper<UUID, Long>(id, recordId), entity, changeType);
+    public Long getTargetRecordId() {
+        return targetRecordId;
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/EntityHistoryBinder.java b/util/src/main/java/com/ning/billing/util/dao/EntityHistoryBinder.java
new file mode 100644
index 0000000..a9435a8
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/EntityHistoryBinder.java
@@ -0,0 +1,78 @@
+/*
+ * 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
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationTargetException;
+
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.util.entity.Entity;
+
+@BindingAnnotation(EntityHistoryBinder.EntityHistoryBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface EntityHistoryBinder {
+
+
+    public static class EntityHistoryBinderFactory<T extends Entity> implements BinderFactory {
+
+        private static final Logger logger = LoggerFactory.getLogger(EntityHistoryBinder.class);
+
+        @Override
+        public Binder build(final Annotation annotation) {
+            return new Binder<EntityHistoryBinder, EntityHistory<T>>() {
+
+
+                @Override
+                public void bind(final SQLStatement<?> q, final EntityHistoryBinder bind, final EntityHistory<T> history) {
+                    try {
+                        // Emulate @BndBean
+                        final Entity arg = history.getEntity();
+                        final BeanInfo infos = Introspector.getBeanInfo(arg.getClass());
+                        final PropertyDescriptor[] props = infos.getPropertyDescriptors();
+                        for (PropertyDescriptor prop : props) {
+                            q.bind(prop.getName(), prop.getReadMethod().invoke(arg));
+                        }
+                        q.bind("id", history.getId());
+                        q.bind("targetRecordId", history.getTargetRecordId());
+                        q.bind("changeType", history.getChangeType().toString());
+                    } catch (IntrospectionException e) {
+                        logger.warn(e.getMessage());
+                    } catch (InvocationTargetException e) {
+                        logger.warn(e.getMessage());
+                    } catch (IllegalAccessException e) {
+                        logger.warn(e.getMessage());
+                    }
+                }
+            };
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/EnumArgumentFactory.java b/util/src/main/java/com/ning/billing/util/dao/EnumArgumentFactory.java
new file mode 100644
index 0000000..aa8dbb2
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/EnumArgumentFactory.java
@@ -0,0 +1,61 @@
+/*
+ * 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
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.Argument;
+import org.skife.jdbi.v2.tweak.ArgumentFactory;
+
+public class EnumArgumentFactory implements ArgumentFactory<Enum> {
+
+    @Override
+    public Argument build(final Class<?> expectedType, final Enum value, final StatementContext ctx) {
+        return new StringArgument(value.toString());
+    }
+
+    class StringArgument implements Argument {
+
+        private final String value;
+
+        StringArgument(final String value) {
+            this.value = value;
+        }
+
+        public void apply(final int position, final PreparedStatement statement, final StatementContext ctx) throws SQLException {
+            if (value != null) {
+                statement.setString(position, value);
+            } else {
+                statement.setNull(position, Types.VARCHAR);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "'" + value + "'";
+        }
+    }
+
+    @Override
+    public boolean accepts(final Class expectedType, final Object value, final StatementContext ctx) {
+        return value != null && value.getClass().isEnum();
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/HistorySqlDao.java b/util/src/main/java/com/ning/billing/util/dao/HistorySqlDao.java
index 8976541..7822434 100644
--- a/util/src/main/java/com/ning/billing/util/dao/HistorySqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/HistorySqlDao.java
@@ -18,6 +18,7 @@ package com.ning.billing.util.dao;
 
 import java.util.List;
 
+import org.skife.jdbi.v2.sqlobject.BindBean;
 import org.skife.jdbi.v2.sqlobject.SqlBatch;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
@@ -28,10 +29,10 @@ import com.ning.billing.util.entity.Entity;
 public interface HistorySqlDao<T extends Entity> {
 
     @SqlBatch(transactional = false)
-    public void batchAddHistoryFromTransaction(List<EntityHistory<T>> histories,
+    public void batchAddHistoryFromTransaction(List<EntityHistory> histories,
                                                @InternalTenantContextBinder InternalCallContext context);
 
     @SqlUpdate
-    public void addHistoryFromTransaction(EntityHistory<T> history,
-                                          @InternalTenantContextBinder InternalCallContext context);
+    public void addHistoryFromTransaction(@EntityHistoryBinder EntityHistory<T> history,
+                                          @BindBean InternalCallContext context);
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/UUIDArgumentFactory.java b/util/src/main/java/com/ning/billing/util/dao/UUIDArgumentFactory.java
new file mode 100644
index 0000000..385314b
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/UUIDArgumentFactory.java
@@ -0,0 +1,66 @@
+/*
+ * 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
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.Argument;
+import org.skife.jdbi.v2.tweak.ArgumentFactory;
+
+public class UUIDArgumentFactory implements ArgumentFactory<UUID> {
+
+    @Override
+    public boolean accepts(final Class<?> expectedType, final Object value, final StatementContext ctx) {
+        return value instanceof UUID;
+    }
+
+    @Override
+    public Argument build(final Class<?> expectedType, final UUID value, final StatementContext ctx) {
+        return new UUIDArgument(value);
+    }
+
+    public class UUIDArgument implements Argument {
+
+        private final UUID value;
+
+        public UUIDArgument(final UUID value) {
+            this.value = value;
+        }
+
+        @Override
+        public void apply(final int position, final PreparedStatement statement, final StatementContext ctx) throws SQLException {
+            if (value != null) {
+                statement.setString(position, value.toString());
+            } else {
+                statement.setNull(position, Types.VARCHAR);
+            }
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("UUIDArgument");
+            sb.append("{value=").append(value);
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
index b8aee42..5ddcc53 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
@@ -26,6 +26,7 @@ import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
+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.callcontext.InternalTenantContextBinder;
@@ -37,8 +38,9 @@ import com.ning.billing.util.entity.EntityPersistenceException;
 public interface EntitySqlDao<T extends Entity> extends AuditSqlDao, HistorySqlDao<T>, Transmogrifier, Transactional<EntitySqlDao<T>>, CloseMe {
 
     @SqlUpdate
+    @Audited(ChangeType.INSERT)
     public void create(@BindBean final T entity,
-                       @InternalTenantContextBinder final InternalCallContext context) throws EntityPersistenceException;
+                       @BindBean final InternalCallContext context) throws EntityPersistenceException;
 
     @SqlQuery
     public T getById(@Bind("id") final String id,
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 7502ef7..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
@@ -19,17 +19,18 @@ package com.ning.billing.util.entity.dao;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import org.skife.jdbi.v2.exceptions.DBIException;
 import org.skife.jdbi.v2.sqlobject.Bind;
 
 import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.InternalCallContext;
-import com.ning.billing.util.callcontext.InternalTenantContextBinder;
 import com.ning.billing.util.dao.EntityAudit;
 import com.ning.billing.util.dao.EntityHistory;
 import com.ning.billing.util.dao.TableName;
@@ -199,12 +200,7 @@ public class EntitySqlDaoWrapperInvocationHandler<T extends EntitySqlDao<U>, U e
             if (!(arg instanceof InternalCallContext)) {
                 continue;
             }
-
-            for (final Annotation annotation : parameterAnnotations[i]) {
-                if (InternalTenantContextBinder.class.equals(annotation.annotationType())) {
-                    return (InternalCallContext) arg;
-                }
-            }
+            return (InternalCallContext) arg;
         }
 
         return null;
@@ -222,14 +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) {
-        final EntityHistory<U> history = new EntityHistory<U>(entity.getId(), entityRecordId, entity, changeType);
+        // 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/entity/EntityBase.java b/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
index 4b8810c..4babfbe 100644
--- a/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
+++ b/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
@@ -42,6 +42,12 @@ public abstract class EntityBase implements Entity {
         this.updatedDate = updatedDate;
     }
 
+    public EntityBase(final EntityBase target) {
+        this.id = UUID.randomUUID();
+        this.createdDate = target.getCreatedDate();
+        this.updatedDate = target.getUpdatedDate();
+    }
+
     @Override
     public UUID getId() {
         return id;
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 2052921..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
@@ -35,6 +35,7 @@ import org.skife.jdbi.v2.sqlobject.BinderFactory;
 import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterArgumentFactory;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
@@ -42,7 +43,10 @@ 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.callcontext.InternalTenantContextBinder;
+import com.ning.billing.util.dao.DateTimeArgumentFactory;
 import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.EnumArgumentFactory;
+import com.ning.billing.util.dao.UUIDArgumentFactory;
 import com.ning.billing.util.entity.dao.Audited;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
@@ -53,11 +57,6 @@ import com.ning.billing.util.tag.TagDefinition;
 @RegisterMapper(TagDefinitionSqlDao.TagDefinitionMapper.class)
 public interface TagDefinitionSqlDao extends EntitySqlDao<TagDefinition> {
 
-    @Override
-    @SqlUpdate
-    @Audited(ChangeType.INSERT)
-    public void create(@TagDefinitionBinder final TagDefinition entity,
-                       @InternalTenantContextBinder final InternalCallContext context);
 
     @SqlQuery
     public TagDefinition getByName(@Bind("name") final String definitionName,
@@ -76,10 +75,6 @@ public interface TagDefinitionSqlDao extends EntitySqlDao<TagDefinition> {
     public List<TagDefinition> getByIds(@UUIDCollectionBinder final Collection<String> definitionIds,
                                         @InternalTenantContextBinder final InternalTenantContext context);
 
-    @Override
-    @SqlUpdate
-    public void addHistoryFromTransaction(@TagDefinitionHistoryBinder final EntityHistory<TagDefinition> tagDefinition,
-                                          @InternalTenantContextBinder final InternalCallContext context);
 
     public class TagDefinitionMapper implements ResultSetMapper<TagDefinition> {
 
@@ -92,49 +87,4 @@ public interface TagDefinitionSqlDao extends EntitySqlDao<TagDefinition> {
         }
     }
 
-    @BindingAnnotation(TagDefinitionBinder.TagDefinitionBinderFactory.class)
-    @Retention(RetentionPolicy.RUNTIME)
-    @Target({ElementType.PARAMETER})
-    public @interface TagDefinitionBinder {
-
-        public static class TagDefinitionBinderFactory implements BinderFactory {
-
-            @Override
-            public Binder build(final Annotation annotation) {
-                return new Binder<TagDefinitionBinder, TagDefinition>() {
-                    @Override
-                    public void bind(final SQLStatement q, final TagDefinitionBinder bind, final TagDefinition tagDefinition) {
-                        q.bind("id", tagDefinition.getId().toString());
-                        q.bind("name", tagDefinition.getName());
-                        q.bind("description", tagDefinition.getDescription());
-                    }
-                };
-            }
-        }
-    }
-
-    @BindingAnnotation(TagDefinitionHistoryBinder.TagDefinitionHistoryBinderFactory.class)
-    @Retention(RetentionPolicy.RUNTIME)
-    @Target({ElementType.PARAMETER})
-    public @interface TagDefinitionHistoryBinder {
-
-        public static class TagDefinitionHistoryBinderFactory implements BinderFactory {
-
-            @Override
-            public Binder<TagDefinitionHistoryBinder, EntityHistory<TagDefinition>> build(final Annotation annotation) {
-                return new Binder<TagDefinitionHistoryBinder, EntityHistory<TagDefinition>>() {
-                    @Override
-                    public void bind(final SQLStatement<?> q, final TagDefinitionHistoryBinder bind, final EntityHistory<TagDefinition> history) {
-                        q.bind("recordId", history.getValue());
-                        q.bind("changeType", history.getChangeType().toString());
-
-                        final TagDefinition tagDefinition = history.getEntity();
-                        q.bind("id", tagDefinition.getId().toString());
-                        q.bind("name", tagDefinition.getName());
-                        q.bind("description", tagDefinition.getDescription());
-                    }
-                };
-            }
-        }
-    }
 }
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 11d279e..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
@@ -40,7 +40,8 @@ public @interface TagHistoryBinder {
             return new Binder<TagHistoryBinder, EntityHistory<Tag>>() {
                 @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/customfield/dao/CustomFieldSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
index 74421f0..018104e 100644
--- a/util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
@@ -11,6 +11,15 @@ tableFields(prefix) ::= <<
 , <prefix>updated_date
 >>
 
+tableValues() ::= <<
+  :objectId
+, :objectType
+, :createdBy
+, :createdDate
+, :updatedBy
+, :updatedDate
+>>
+
 historyTableName() ::= "custom_field_history"
 
 updateFromTransaction() ::= <<
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 25758e8..11af132 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -58,20 +58,21 @@ CREATE INDEX tag_definitions_tenant_record_id ON tag_definitions(tenant_record_i
 
 DROP TABLE IF EXISTS tag_definition_history;
 CREATE TABLE tag_definition_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,
     name varchar(30) NOT NULL,
-    created_by varchar(50),
     description varchar(200),
     change_type char(6) NOT NULL,
+    created_by varchar(50),
+    created_date datetime NOT NULL,
     updated_by varchar(50) NOT NULL,
-    date datetime NOT NULL,
+    updated_date datetime NOT NULL,
     tenant_record_id int(11) unsigned default null,
-    PRIMARY KEY(history_record_id)
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
 CREATE INDEX tag_definition_history_id ON tag_definition_history(id);
-CREATE INDEX tag_definition_history_record_id ON tag_definition_history(record_id);
+CREATE INDEX tag_definition_history_target_record_id ON tag_definition_history(target_record_id);
 CREATE INDEX tag_definition_history_name ON tag_definition_history(name);
 CREATE INDEX tag_definition_history_tenant_record_id ON tag_definition_history(tenant_record_id);
 
@@ -84,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)
@@ -95,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);
 
@@ -155,7 +160,7 @@ CREATE TABLE audit_log (
     table_name varchar(50) NOT NULL,
     target_record_id int(11) NOT NULL,
     change_type char(6) NOT NULL,
-    changed_by varchar(50) NOT NULL,
+    created_by varchar(50) NOT NULL,
     reason_code varchar(255) DEFAULT NULL,
     comments varchar(255) DEFAULT NULL,
     user_token char(36),
@@ -165,7 +170,7 @@ CREATE TABLE audit_log (
     PRIMARY KEY(record_id)
 ) ENGINE=innodb;
 CREATE INDEX audit_log_fetch_target_record_id ON audit_log(table_name, target_record_id);
-CREATE INDEX audit_log_user_name ON audit_log(changed_by);
+CREATE INDEX audit_log_user_name ON audit_log(created_by);
 CREATE INDEX audit_log_tenant_account_record_id ON audit_log(tenant_record_id, account_record_id);
 
 DROP TABLE IF EXISTS bus_events;
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 6d3b9e4..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
@@ -4,16 +4,24 @@ group EntitySqlDao;
 
 tableName() ::= ""
 
-/** Leave out id, account_record_id and tenant_record_id */
+/** Leave out id, account_record_id and tenant_record_id **/
 tableFields(prefix) ::= ""
 
 tableValues() ::= ""
 
 historyTableName() ::= ""
 
-historyTableFields(prefix) ::= "<tableFields(prefix)>"
+historyTableFields(prefix) ::= <<
+  <targetRecordIdField(prefix)>
+, <changeTypeField(prefix)>
+, <tableFields(prefix)>
+>>
 
-historyTableValues() ::= "<tableValues()>"
+historyTableValues() ::= <<
+  <targetRecordIdValue()>
+, <changeTypeValue()>
+, <tableValues()>
+>>
 
 /****************************************************/
 
@@ -21,85 +29,96 @@ idField(prefix) ::= <<
 <prefix>id
 >>
 
+idValue() ::= ":id"
+
 recordIdField(prefix) ::= <<
 <prefix>record_id
 >>
 
-historyRecordIdField(prefix) ::= <<
-<prefix>history_record_id
+recordIdValue() ::= ":recordId"
+
+changeTypeField(prefix) ::= <<
+<prefix>change_type
 >>
 
-/** Override this if the Entity isn't tied to an account */
+changeTypeValue() ::= ":changeType"
+
+targetRecordIdField(prefix) ::= <<
+<prefix>target_record_id
+>>
+
+targetRecordIdValue() ::= ":targetRecordId"
+
+/** Override this if the Entity isn't tied to an account **/
+
+
 accountRecordIdField(prefix) ::= <<
 <prefix>account_record_id
 >>
 
+accountRecordIdFieldWithComma(prefix) ::= <<
+, <accountRecordIdField(prefix)>
+>>
+
 accountRecordIdValue() ::= ":accountRecordId"
 
+accountRecordIdValueWithComma() ::= <<
+, <accountRecordIdValue()>
+>>
+
 tenantRecordIdField(prefix) ::= <<
 <prefix>tenant_record_id
 >>
 
+tenantRecordIdFieldWithComma(prefix) ::= <<
+, <tenantRecordIdField(prefix)>
+>>
+
+
 tenantRecordIdValue() ::= ":tenantRecordId"
 
+tenantRecordIdValueWithComma() ::= <<
+, <tenantRecordIdValue()>
+>>
+
 allTableFields(prefix) ::= <<
   <recordIdField(prefix)>
 , <idField(prefix)>
 , <tableFields(prefix)>
-<if(accountRecordIdField(prefix))>, <accountRecordIdField(prefix)><endif>
-, <tenantRecordIdField(prefix)>
+<accountRecordIdFieldWithComma(prefix)>
+<tenantRecordIdFieldWithComma(prefix)>
+>>
+
+
+
+allTableValues() ::= <<
+  <recordIdValue()>
+, <idValue()>
+, <tableValues()>
+<accountRecordIdValueWithComma()>
+<tenantRecordIdValueWithComma()>
 >>
 
-/** TODO  history tables should not start with history_record_id, instead: record_id, id, target_record_id  **/
+
 allHistoryTableFields(prefix) ::= <<
-  <historyRecordIdField(prefix)>
-, <recordIdField(prefix)>
+  <recordIdField(prefix)>
 , <idField(prefix)>
+, <targetRecordIdField(prefix)>
 , <historyTableFields(prefix)>
-<if(accountRecordIdField(prefix))>, <accountRecordIdField(prefix)><endif>
-, <tenantRecordIdField(prefix)>
+<accountRecordIdFieldWithComma(prefix)>
+<tenantRecordIdFieldWithComma(prefix)>
 >>
 
 allHistoryTableValues() ::= <<
-  :recordId
-, :id
+  <recordIdValue()>
+, <idValue()>
+,  <targetRecordIdValue()>
 , <historyTableValues()>
-<if(accountRecordIdField(""))>, <accountRecordIdValue()><endif>
-<if(tenantRecordIdField(""))>, <tenantRecordIdValue()><endif>
->>
-
-auditTableName() ::= "audit_log"
-
-
-auditTableFields(prefix) ::= <<
-  <prefix>id
-, <prefix>table_name
-, <prefix>target_record_id
-, <prefix>change_type
-, <prefix>changed_by
-, <prefix>reason_code
-, <prefix>comments
-, <prefix>user_token
-, <prefix>created_date
-, <accountRecordIdField(prefix)>
-, <tenantRecordIdField(prefix)>
+<accountRecordIdValueWithComma()>
+<tenantRecordIdValueWithComma()>
 >>
 
 
-auditTableValues(prefix) ::= <<
-  :id
-, :tableName
-, :targetRecordId
-, :changeType
-, :changedBy
-, :reasonCode
-, :comment
-, :userToken
-, :createdDate
-, <accountRecordIdValue()>
-, <tenantRecordIdValue()>
->>
-
 /** Macros used for multi-tenancy (almost any query should use them!) */
 CHECK_TENANT(prefix) ::= "<prefix>tenant_record_id = :tenantRecordId"
 AND_CHECK_TENANT(prefix) ::= "and <CHECK_TENANT(prefix)>"
@@ -131,15 +150,34 @@ where <idField("t.")> = :id
 ;
 >>
 
+getRecordIdForTable(tableName) ::= <<
+select
+  <recordIdField("t.")>
+from <tableName> t
+where <idField("t.")> = :id
+<AND_CHECK_TENANT("t.")>
+;
+>>
+
 getHistoryRecordId(recordId) ::= <<
 select
-  max(<historyRecordIdField("t.")>)
+  max(<recordIdField("t.")>)
 from <tableName()> t
 where <recordIdField("t.")> = :recordId
 <AND_CHECK_TENANT("t.")>
 ;
 >>
 
+
+getHistoryRecordIdsForTable(historyTableName) ::= <<
+select
+  <recordIdField("t.")>
+from <historyTableName> t
+where <targetRecordIdField("t.")> = :targetRecordId
+<AND_CHECK_TENANT("t.")>
+;
+>>
+
 get(limit) ::= <<
 select
 <allTableFields("t.")>
@@ -149,25 +187,71 @@ where <CHECK_TENANT("t.")>
 ;
 >>
 
-test() ::= <<
-select
-<allTableFields("t.")>
-from <tableName()> t
-where <CHECK_TENANT("t.")>
-limit 1
+create() ::= <<
+insert into <tableName()> (
+  <idField()>
+, <tableFields()>
+<accountRecordIdFieldWithComma()>
+<tenantRecordIdFieldWithComma()>
+)
+values (
+  <idValue()>
+, <tableValues()>
+<accountRecordIdValueWithComma()>
+<tenantRecordIdValueWithComma()>
+)
 ;
 >>
 
+/** Audits, History **/
+auditTableName() ::= "audit_log"
+
+auditTableFields(prefix) ::= <<
+  <prefix>id
+, <prefix>table_name
+, <prefix>target_record_id
+, <prefix>change_type
+, <prefix>created_by
+, <prefix>reason_code
+, <prefix>comments
+, <prefix>user_token
+, <prefix>created_date
+<if(accountRecordIdField(prefix))>, <accountRecordIdField(prefix)><endif>
+<if(tenantRecordIdField(prefix))>, <tenantRecordIdField(prefix)><endif>
+>>
+
+auditTableValues() ::= <<
+  :id
+, :tableName
+, :targetRecordId
+, :changeType
+, :createdBy
+, :reasonCode
+, :comment
+, :userToken
+, :createdDate
+<if(accountRecordIdField(""))>, <accountRecordIdValue()><endif>
+<if(tenantRecordIdField(""))>, <tenantRecordIdValue()><endif>
+>>
+
+
 addHistoryFromTransaction() ::= <<
 insert into <historyTableName()> (
-<allHistoryTableFields()>
+  <idField()>
+, <historyTableFields()>
+<accountRecordIdFieldWithComma()>
+<tenantRecordIdFieldWithComma()>
 )
 values (
-<allHistoryTableValues()>
+  <idValue()>
+, <historyTableValues()>
+<accountRecordIdValueWithComma()>
+<tenantRecordIdValueWithComma()>
 )
 ;
 >>
 
+
 insertAuditFromTransaction() ::= <<
 insert into <auditTableName()> (
 <auditTableFields()>
@@ -177,3 +261,23 @@ values (
 )
 ;
 >>
+
+getAuditLogsForTargetRecordId() ::= <<
+select
+  <auditTableFields("t.")>
+from <auditTableName()> t
+where t.target_record_id = :targetRecordId
+and t.table_name = :tableName
+<AND_CHECK_TENANT("t.")>
+order by created_date ASC
+;
+>>
+
+test() ::= <<
+select
+<allTableFields("t.")>
+from <tableName()> t
+where <CHECK_TENANT("t.")>
+limit 1
+;
+>>
diff --git a/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
index 2e356eb..9492ebd 100644
--- a/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
@@ -11,8 +11,19 @@ tableFields(prefix) ::= <<
 , <prefix>updated_date
 >>
 
-/** No account_record_id field */
-accountRecordIdField(prefix) ::= ""
+tableValues() ::= <<
+  :name
+, :description
+, :createdBy
+, :createdDate
+, :updatedBy
+, :updatedDate
+>>
+
+accountRecordIdFieldWithComma() ::= ""
+
+accountRecordIdValueWithComma() ::= ""
+
 
 historyTableName() ::= "tag_definition_history"
 
@@ -31,7 +42,7 @@ tagDefinitionUsageCount() ::= <<
 >>
 
 getByName() ::= <<
-  SELECT <fields()>
+  SELECT <allTableFields()>
    FROM tag_definitions
   WHERE name = :name
   <AND_CHECK_TENANT()>
@@ -39,7 +50,7 @@ getByName() ::= <<
 >>
 
 getByIds(tag_definition_ids) ::= <<
-  SELECT <fields()>
+  SELECT <allTableFields()>
   FROM tag_definitions
   WHERE id IN (<tag_definition_ids: {id | :id_<i0>}; separator="," >)
   <AND_CHECK_TENANT()>
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 e23d565..c4d06e2 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
@@ -117,7 +117,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());
@@ -135,7 +135,7 @@ public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
         Assert.assertEquals(auditLogs.get(0).getChangeType(), ChangeType.INSERT);
         Assert.assertEquals(auditLogs.get(0).getComment(), internalCallContext.getComment());
         Assert.assertEquals(auditLogs.get(0).getReasonCode(), internalCallContext.getReasonCode());
-        Assert.assertEquals(auditLogs.get(0).getUserName(), internalCallContext.getUserName());
+        Assert.assertEquals(auditLogs.get(0).getUserName(), internalCallContext.getCreatedBy());
         Assert.assertNotNull(auditLogs.get(0).getCreatedDate());
     }
 }
diff --git a/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java b/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java
index 5564b47..3b4c06d 100644
--- a/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java
+++ b/util/src/test/java/com/ning/billing/util/callcontext/TestInternalCallContextFactory.java
@@ -100,7 +100,7 @@ public class TestInternalCallContextFactory extends UtilTestSuiteWithEmbeddedDB 
         Assert.assertEquals(context.getCreatedDate(), callContext.getCreatedDate());
         Assert.assertEquals(context.getReasonCode(), callContext.getReasonCode());
         Assert.assertEquals(context.getUpdatedDate(), callContext.getUpdatedDate());
-        Assert.assertEquals(context.getUserName(), callContext.getUserName());
+        Assert.assertEquals(context.getCreatedBy(), callContext.getUserName());
         Assert.assertEquals(context.getUserToken(), callContext.getUserToken());
         Assert.assertEquals(context.getUserType(), callContext.getUserType());
         // Our test callContext doesn't have a tenant id
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 00f9931..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.getUserName());
-    }
-
-    @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.getUserName());
-    }
-
-    @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);
-    }
 }