killbill-memoizeit

Merge branch 'integration' of github.com:ning/killbill

6/13/2012 5:11:06 AM

Changes

Details

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 e846a42..5e51ecd 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
@@ -28,6 +28,7 @@ import java.util.UUID;
 
 import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.account.api.DefaultAccountEmail;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.customfield.StringCustomField;
 import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
@@ -146,7 +147,7 @@ public class TestAccountDao extends AccountDaoTestBase {
     }
 
     @Test
-    public void testTags() throws EntityPersistenceException {
+    public void testTags() throws EntityPersistenceException, TagApiException {
         Account account = createTestAccount(1);
         TagDefinition definition = new DefaultTagDefinition("Test Tag", "For testing only", false);
         TagDefinitionSqlDao tagDescriptionDao = dbi.onDemand(TagDefinitionSqlDao.class);
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
index 56ee93f..1b8afb3 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
@@ -17,6 +17,7 @@
 package com.ning.billing.invoice.api;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
 
@@ -40,9 +41,9 @@ public interface InvoiceUserApi {
     
     public Invoice triggerInvoiceGeneration(UUID accountId, DateTime targetDate, boolean dryRun, CallContext context) throws InvoiceApiException;
 
-    public void tagInvoiceAsWrittenOff(UUID invoiceId, CallContext context);
+    public void tagInvoiceAsWrittenOff(UUID invoiceId, CallContext context) throws TagApiException;
 
-    public void tagInvoiceAsNotWrittenOff(UUID invoiceId, CallContext context) throws InvoiceApiException;
+    public void tagInvoiceAsNotWrittenOff(UUID invoiceId, CallContext context) throws TagApiException;
 
     public InvoiceItem getCreditById(UUID creditId) throws InvoiceApiException;
 
diff --git a/api/src/main/java/com/ning/billing/util/api/TagApiException.java b/api/src/main/java/com/ning/billing/util/api/TagApiException.java
new file mode 100644
index 0000000..7b3c032
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/api/TagApiException.java
@@ -0,0 +1,36 @@
+/*
+ * 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.api;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+
+public class TagApiException extends BillingExceptionBase {
+    private static final long serialVersionUID = 1L;
+
+    public TagApiException(final Throwable cause, final int code, final String msg) {
+        super(cause, code, msg);
+    }
+
+    public TagApiException(final Throwable cause, final ErrorCode code, final Object... args) {
+        super(cause, code, args);
+    }
+
+    public TagApiException(final ErrorCode code, final Object... args) {
+        super(code, args);
+    }
+}
diff --git a/api/src/main/java/com/ning/billing/util/api/TagDefinitionApiException.java b/api/src/main/java/com/ning/billing/util/api/TagDefinitionApiException.java
index a67f1ad..1b080d5 100644
--- a/api/src/main/java/com/ning/billing/util/api/TagDefinitionApiException.java
+++ b/api/src/main/java/com/ning/billing/util/api/TagDefinitionApiException.java
@@ -22,15 +22,15 @@ import com.ning.billing.ErrorCode;
 public class TagDefinitionApiException extends BillingExceptionBase {
     private static final long serialVersionUID = 1L;
 
-    public TagDefinitionApiException(Throwable cause, int code, final String msg) {
+    public TagDefinitionApiException(final Throwable cause, final int code, final String msg) {
         super(cause, code, msg);
     }
 
-    public TagDefinitionApiException(Throwable cause, ErrorCode code, final Object... args) {
+    public TagDefinitionApiException(final Throwable cause, final ErrorCode code, final Object... args) {
         super(cause, code, args);
     }
 
-    public TagDefinitionApiException(ErrorCode code, final Object... args) {
+    public TagDefinitionApiException(final ErrorCode code, final Object... args) {
         super(code, args);
     }
-}
\ No newline at end of file
+}
diff --git a/api/src/main/java/com/ning/billing/util/api/TagUserApi.java b/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
index 2be6d6d..331cce4 100644
--- a/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
+++ b/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
@@ -54,13 +54,13 @@ public interface TagUserApi {
      */
     public TagDefinition getTagDefinition(String name) throws TagDefinitionApiException;
 
-    public void addTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions, CallContext context);
+    public void addTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions, CallContext context) throws TagApiException;
 
-    public void addTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition, CallContext context);
+    public void addTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition, CallContext context) throws TagApiException;
 
-    public void removeTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions, CallContext context);
+    public void removeTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions, CallContext context) throws TagApiException;
 
-    public void removeTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition, CallContext context);
+    public void removeTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition, CallContext context) throws TagApiException;
 
     public Map<String, Tag> getTags(UUID objectId, ObjectType objectType);
 }
diff --git a/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java b/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
index d35e011..88f9f1a 100644
--- a/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
+++ b/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
@@ -16,9 +16,11 @@
 
 package com.ning.billing.util.tag;
 
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import com.ning.billing.util.entity.Entity;
 
 // TODO: needs to surface created date, created by, isControlTag
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
 public interface TagDefinition extends Entity {
     String getName();
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
index 3b462f1..08ba27a 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
@@ -40,6 +40,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.api.TagUserApi;
 import com.ning.billing.util.dao.ObjectType;
@@ -166,7 +167,7 @@ public class TestIntegrationWithAutoInvoiceOffTag extends TestIntegrationBase {
     }
 
 
-    private void addTag(UUID id, ObjectType type) throws TagDefinitionApiException {
+    private void addTag(UUID id, ObjectType type) throws TagDefinitionApiException, TagApiException {
         TagDefinition def = tagApi.getTagDefinition(ControlTagType.AUTO_INVOICING_OFF.name());
         tagApi.addTag(id, type, def, context);
         Map<String,Tag> tags = tagApi.getTags(id, type);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 7f2ced3..7a231a4 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -22,6 +22,7 @@ import java.util.UUID;
 
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
 
@@ -82,12 +83,12 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
 	}
 
     @Override
-    public void tagInvoiceAsWrittenOff(final UUID invoiceId, final CallContext context) {
+    public void tagInvoiceAsWrittenOff(final UUID invoiceId, final CallContext context) throws TagApiException {
         dao.setWrittenOff(invoiceId, context);
     }
 
     @Override
-    public void tagInvoiceAsNotWrittenOff(final UUID invoiceId, final CallContext context) throws InvoiceApiException {
+    public void tagInvoiceAsNotWrittenOff(final UUID invoiceId, final CallContext context) throws TagApiException {
         dao.removeWrittenOff(invoiceId, context);
     }
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index c3bd916..b3145b5 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -39,6 +39,7 @@ import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
 import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
 import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagUserApi;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.dao.EntityAudit;
@@ -260,12 +261,12 @@ public class DefaultInvoiceDao implements InvoiceDao {
     }
 
     @Override
-    public void setWrittenOff(final UUID invoiceId, final CallContext context) {
+    public void setWrittenOff(final UUID invoiceId, final CallContext context) throws TagApiException {
         tagUserApi.addTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.toTagDefinition(), context);
     }
 
     @Override
-    public void removeWrittenOff(final UUID invoiceId, final CallContext context) throws InvoiceApiException {
+    public void removeWrittenOff(final UUID invoiceId, final CallContext context) throws TagApiException {
         tagUserApi.removeTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.toTagDefinition(), context);
     }
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
index c7e520b..20c3c53 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
@@ -21,6 +21,7 @@ import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
 
@@ -55,9 +56,9 @@ public interface InvoiceDao {
 
 	List<Invoice> getAllInvoicesByAccount(final UUID accountId);
 
-    void setWrittenOff(final UUID invoiceId, final CallContext context);
+    void setWrittenOff(final UUID invoiceId, final CallContext context) throws TagApiException;
 
-    void removeWrittenOff(final UUID invoiceId, final CallContext context) throws InvoiceApiException;
+    void removeWrittenOff(final UUID invoiceId, final CallContext context) throws TagApiException;
 
     void postChargeback(final UUID invoicePaymentId, final BigDecimal amount, final CallContext context) throws InvoiceApiException;
 
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index e4ab210..a47a518 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -56,6 +56,7 @@ import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.junction.api.BillingEventSet;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.Tag;
@@ -632,7 +633,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
     }
 
     @Test
-    public void testAddingWrittenOffTag() throws InvoiceApiException {
+    public void testAddingWrittenOffTag() throws InvoiceApiException, TagApiException {
         Subscription subscription = getZombieSubscription();
 
         Plan plan = BrainDeadProxyFactory.createBrainDeadProxyFor(Plan.class);
@@ -663,7 +664,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
     }
 
     @Test
-    public void testRemoveWrittenOffTag() throws InvoiceApiException {
+    public void testRemoveWrittenOffTag() throws InvoiceApiException, TagApiException {
         Subscription subscription = getZombieSubscription();
 
         Plan plan = BrainDeadProxyFactory.createBrainDeadProxyFor(Plan.class);
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
index a302336..33d778c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -23,6 +23,7 @@ import com.ning.billing.jaxrs.json.CustomFieldJson;
 import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
 import com.ning.billing.jaxrs.util.TagHelper;
 import com.ning.billing.util.api.CustomFieldUserApi;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.api.TagUserApi;
 import com.ning.billing.util.callcontext.CallContext;
@@ -87,6 +88,8 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
             return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
         } catch (TagDefinitionApiException e) {
             return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
+        } catch (TagApiException e) {
+            return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
         }
     }
 
@@ -105,6 +108,8 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
             return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
         } catch (TagDefinitionApiException e) {
             return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
+        } catch (TagApiException e) {
+            return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
         }
     }
 
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 93de7f8..075e10e 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
@@ -21,6 +21,7 @@ import java.util.Map;
 import java.util.UUID;
 
 import com.google.inject.Inject;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.api.TagUserApi;
 import com.ning.billing.util.callcontext.CallContext;
@@ -62,22 +63,25 @@ public class DefaultTagUserApi implements TagUserApi {
     }
 
     @Override
-    public void addTags(final UUID objectId, final ObjectType objectType, final List<TagDefinition> tagDefinitions, final CallContext context) {
-        tagDao.insertTags(objectId, objectType, tagDefinitions, context);
+    public void addTags(final UUID objectId, final ObjectType objectType, final List<TagDefinition> tagDefinitions, final CallContext context) throws TagApiException {
+        // TODO: consider making this batch
+        for (final TagDefinition tagDefinition : tagDefinitions) {
+            tagDao.insertTag(objectId, objectType, tagDefinition, context);
+        }
     }
 
     @Override
-    public void addTag(final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final CallContext context) {
+    public void addTag(final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final CallContext context) throws TagApiException {
         tagDao.insertTag(objectId, objectType, tagDefinition, context);
     }
 
     @Override
-    public void removeTag(final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final CallContext context) {
+    public void removeTag(final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final CallContext context) throws TagApiException {
         tagDao.deleteTag(objectId, objectType, tagDefinition, context);
     }
 
     @Override
-    public void removeTags(final UUID objectId, final ObjectType objectType, final List<TagDefinition> tagDefinitions, final CallContext context) {
+    public void removeTags(final UUID objectId, final ObjectType objectType, final List<TagDefinition> tagDefinitions, final CallContext context) throws TagApiException {
         // TODO: consider making this batch
         for (final TagDefinition tagDefinition : tagDefinitions) {
             tagDao.deleteTag(objectId, objectType, tagDefinition, context);
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagCreationEvent.java b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagCreationEvent.java
index 2e420ed..3f24ac4 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagCreationEvent.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagCreationEvent.java
@@ -18,6 +18,9 @@ package com.ning.billing.util.tag.api.user;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.ControlTagCreationEvent;
@@ -29,7 +32,12 @@ public class DefaultControlTagCreationEvent implements ControlTagCreationEvent {
     private final TagDefinition tagDefinition;
     private final UUID userToken;
 
-    public DefaultControlTagCreationEvent(final UUID tagId, final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final UUID userToken) {
+    @JsonCreator
+    public DefaultControlTagCreationEvent(@JsonProperty("tagId") final UUID tagId,
+                                          @JsonProperty("objectId") final UUID objectId,
+                                          @JsonProperty("objectType") final ObjectType objectType,
+                                          @JsonProperty("tagDefinition") final TagDefinition tagDefinition,
+                                          @JsonProperty("userToken") final UUID userToken) {
         this.tagId = tagId;
         this.objectId = objectId;
         this.objectType = objectType;
@@ -57,6 +65,7 @@ public class DefaultControlTagCreationEvent implements ControlTagCreationEvent {
         return tagDefinition;
     }
 
+    @JsonIgnore
     @Override
     public BusEventType getBusEventType() {
         return BusEventType.CONTROL_TAG_CREATION;
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDefinitionCreationEvent.java b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDefinitionCreationEvent.java
index b084ac5..f21db81 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDefinitionCreationEvent.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDefinitionCreationEvent.java
@@ -18,23 +18,29 @@ package com.ning.billing.util.tag.api.user;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.ControlTagDefinitionCreationEvent;
 
 public class DefaultControlTagDefinitionCreationEvent implements ControlTagDefinitionCreationEvent {
-    private final UUID tagId;
+    private final UUID tagDefinitionId;
     private final TagDefinition tagDefinition;
     private final UUID userToken;
 
-    public DefaultControlTagDefinitionCreationEvent(final UUID tagId, final TagDefinition tagDefinition, final UUID userToken) {
-        this.tagId = tagId;
+    @JsonCreator
+    public DefaultControlTagDefinitionCreationEvent(@JsonProperty("tagDefinitionId") final UUID tagDefinitionId,
+                                                    @JsonProperty("tagDefinition") final TagDefinition tagDefinition,
+                                                    @JsonProperty("userToken") final UUID userToken) {
+        this.tagDefinitionId = tagDefinitionId;
         this.tagDefinition = tagDefinition;
         this.userToken = userToken;
     }
 
     @Override
     public UUID getTagDefinitionId() {
-        return tagId;
+        return tagDefinitionId;
     }
 
     @Override
@@ -42,6 +48,7 @@ public class DefaultControlTagDefinitionCreationEvent implements ControlTagDefin
         return tagDefinition;
     }
 
+    @JsonIgnore
     @Override
     public BusEventType getBusEventType() {
         return BusEventType.CONTROL_TAGDEFINITION_CREATION;
@@ -57,7 +64,7 @@ public class DefaultControlTagDefinitionCreationEvent implements ControlTagDefin
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultControlTagDefinitionCreationEvent");
         sb.append("{tagDefinition=").append(tagDefinition);
-        sb.append(", tagId=").append(tagId);
+        sb.append(", tagDefinitionId=").append(tagDefinitionId);
         sb.append(", userToken=").append(userToken);
         sb.append('}');
         return sb.toString();
@@ -77,7 +84,7 @@ public class DefaultControlTagDefinitionCreationEvent implements ControlTagDefin
         if (tagDefinition != null ? !tagDefinition.equals(that.tagDefinition) : that.tagDefinition != null) {
             return false;
         }
-        if (tagId != null ? !tagId.equals(that.tagId) : that.tagId != null) {
+        if (tagDefinitionId != null ? !tagDefinitionId.equals(that.tagDefinitionId) : that.tagDefinitionId != null) {
             return false;
         }
         if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
@@ -89,7 +96,7 @@ public class DefaultControlTagDefinitionCreationEvent implements ControlTagDefin
 
     @Override
     public int hashCode() {
-        int result = tagId != null ? tagId.hashCode() : 0;
+        int result = tagDefinitionId != null ? tagDefinitionId.hashCode() : 0;
         result = 31 * result + (tagDefinition != null ? tagDefinition.hashCode() : 0);
         result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
         return result;
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDefinitionDeletionEvent.java b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDefinitionDeletionEvent.java
index 10de711..386b25b 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDefinitionDeletionEvent.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDefinitionDeletionEvent.java
@@ -18,23 +18,29 @@ package com.ning.billing.util.tag.api.user;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.ControlTagDefinitionDeletionEvent;
 
 public class DefaultControlTagDefinitionDeletionEvent implements ControlTagDefinitionDeletionEvent {
-    private final UUID tagId;
+    private final UUID tagDefinitionId;
     private final TagDefinition tagDefinition;
     private final UUID userToken;
 
-    public DefaultControlTagDefinitionDeletionEvent(final UUID tagId, final TagDefinition tagDefinition, final UUID userToken) {
-        this.tagId = tagId;
+    @JsonCreator
+    public DefaultControlTagDefinitionDeletionEvent(@JsonProperty("tagDefinitionId") final UUID tagDefinitionId,
+                                                    @JsonProperty("tagDefinition") final TagDefinition tagDefinition,
+                                                    @JsonProperty("userToken") final UUID userToken) {
+        this.tagDefinitionId = tagDefinitionId;
         this.tagDefinition = tagDefinition;
         this.userToken = userToken;
     }
 
     @Override
     public UUID getTagDefinitionId() {
-        return tagId;
+        return tagDefinitionId;
     }
 
     @Override
@@ -42,6 +48,7 @@ public class DefaultControlTagDefinitionDeletionEvent implements ControlTagDefin
         return tagDefinition;
     }
 
+    @JsonIgnore
     @Override
     public BusEventType getBusEventType() {
         return BusEventType.CONTROL_TAGDEFINITION_DELETION;
@@ -57,7 +64,7 @@ public class DefaultControlTagDefinitionDeletionEvent implements ControlTagDefin
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultControlTagDefinitionDeletionEvent");
         sb.append("{tagDefinition=").append(tagDefinition);
-        sb.append(", tagId=").append(tagId);
+        sb.append(", tagDefinitionId=").append(tagDefinitionId);
         sb.append(", userToken=").append(userToken);
         sb.append('}');
         return sb.toString();
@@ -77,7 +84,7 @@ public class DefaultControlTagDefinitionDeletionEvent implements ControlTagDefin
         if (tagDefinition != null ? !tagDefinition.equals(that.tagDefinition) : that.tagDefinition != null) {
             return false;
         }
-        if (tagId != null ? !tagId.equals(that.tagId) : that.tagId != null) {
+        if (tagDefinitionId != null ? !tagDefinitionId.equals(that.tagDefinitionId) : that.tagDefinitionId != null) {
             return false;
         }
         if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
@@ -89,7 +96,7 @@ public class DefaultControlTagDefinitionDeletionEvent implements ControlTagDefin
 
     @Override
     public int hashCode() {
-        int result = tagId != null ? tagId.hashCode() : 0;
+        int result = tagDefinitionId != null ? tagDefinitionId.hashCode() : 0;
         result = 31 * result + (tagDefinition != null ? tagDefinition.hashCode() : 0);
         result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
         return result;
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDeletionEvent.java b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDeletionEvent.java
index 79f97a9..326d50f 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDeletionEvent.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultControlTagDeletionEvent.java
@@ -18,6 +18,9 @@ package com.ning.billing.util.tag.api.user;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.ControlTagDeletionEvent;
@@ -29,7 +32,12 @@ public class DefaultControlTagDeletionEvent implements ControlTagDeletionEvent {
     final TagDefinition tagDefinition;
     final UUID userToken;
 
-    public DefaultControlTagDeletionEvent(final UUID tagId, final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final UUID userToken) {
+    @JsonCreator
+    public DefaultControlTagDeletionEvent(@JsonProperty("tagId") final UUID tagId,
+                                          @JsonProperty("objectId") final UUID objectId,
+                                          @JsonProperty("objectType") final ObjectType objectType,
+                                          @JsonProperty("tagDefinition") final TagDefinition tagDefinition,
+                                          @JsonProperty("userToken") final UUID userToken) {
         this.tagId = tagId;
         this.objectId = objectId;
         this.objectType = objectType;
@@ -57,6 +65,7 @@ public class DefaultControlTagDeletionEvent implements ControlTagDeletionEvent {
         return tagDefinition;
     }
 
+    @JsonIgnore
     @Override
     public BusEventType getBusEventType() {
         return BusEventType.CONTROL_TAG_DELETION;
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagCreationEvent.java b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagCreationEvent.java
index 634addb..ae386f1 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagCreationEvent.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagCreationEvent.java
@@ -18,6 +18,9 @@ package com.ning.billing.util.tag.api.user;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.UserTagCreationEvent;
@@ -29,7 +32,12 @@ public class DefaultUserTagCreationEvent implements UserTagCreationEvent {
     private final TagDefinition tagDefinition;
     private final UUID userToken;
 
-    public DefaultUserTagCreationEvent(final UUID tagId, final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final UUID userToken) {
+    @JsonCreator
+    public DefaultUserTagCreationEvent(@JsonProperty("tagId") final UUID tagId,
+                                       @JsonProperty("objectId") final UUID objectId,
+                                       @JsonProperty("objectType") final ObjectType objectType,
+                                       @JsonProperty("tagDefinition") final TagDefinition tagDefinition,
+                                       @JsonProperty("userToken") final UUID userToken) {
         this.tagId = tagId;
         this.objectId = objectId;
         this.objectType = objectType;
@@ -57,6 +65,7 @@ public class DefaultUserTagCreationEvent implements UserTagCreationEvent {
         return tagDefinition;
     }
 
+    @JsonIgnore
     @Override
     public BusEventType getBusEventType() {
         return BusEventType.USER_TAG_CREATION;
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDefinitionCreationEvent.java b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDefinitionCreationEvent.java
index eaf2cae..5d86e4b 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDefinitionCreationEvent.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDefinitionCreationEvent.java
@@ -18,23 +18,29 @@ package com.ning.billing.util.tag.api.user;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.UserTagDefinitionCreationEvent;
 
 public class DefaultUserTagDefinitionCreationEvent implements UserTagDefinitionCreationEvent {
-    private final UUID tagId;
+    private final UUID tagDefinitionId;
     private final TagDefinition tagDefinition;
     private final UUID userToken;
 
-    public DefaultUserTagDefinitionCreationEvent(final UUID tagDefinitionId, final TagDefinition tagDefinition, final UUID userToken) {
-        this.tagId = tagDefinitionId;
+    @JsonCreator
+    public DefaultUserTagDefinitionCreationEvent(@JsonProperty("tagDefinitionId") final UUID tagDefinitionId,
+                                                 @JsonProperty("tagDefinition") final TagDefinition tagDefinition,
+                                                 @JsonProperty("userToken") final UUID userToken) {
+        this.tagDefinitionId = tagDefinitionId;
         this.tagDefinition = tagDefinition;
         this.userToken = userToken;
     }
 
     @Override
     public UUID getTagDefinitionId() {
-        return tagId;
+        return tagDefinitionId;
     }
 
     @Override
@@ -42,6 +48,7 @@ public class DefaultUserTagDefinitionCreationEvent implements UserTagDefinitionC
         return tagDefinition;
     }
 
+    @JsonIgnore
     @Override
     public BusEventType getBusEventType() {
         return BusEventType.USER_TAGDEFINITION_CREATION;
@@ -57,7 +64,7 @@ public class DefaultUserTagDefinitionCreationEvent implements UserTagDefinitionC
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultUserTagDefinitionCreationEvent");
         sb.append("{tagDefinition=").append(tagDefinition);
-        sb.append(", tagId=").append(tagId);
+        sb.append(", tagDefinitionId=").append(tagDefinitionId);
         sb.append(", userToken=").append(userToken);
         sb.append('}');
         return sb.toString();
@@ -77,7 +84,7 @@ public class DefaultUserTagDefinitionCreationEvent implements UserTagDefinitionC
         if (tagDefinition != null ? !tagDefinition.equals(that.tagDefinition) : that.tagDefinition != null) {
             return false;
         }
-        if (tagId != null ? !tagId.equals(that.tagId) : that.tagId != null) {
+        if (tagDefinitionId != null ? !tagDefinitionId.equals(that.tagDefinitionId) : that.tagDefinitionId != null) {
             return false;
         }
         if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
@@ -89,7 +96,7 @@ public class DefaultUserTagDefinitionCreationEvent implements UserTagDefinitionC
 
     @Override
     public int hashCode() {
-        int result = tagId != null ? tagId.hashCode() : 0;
+        int result = tagDefinitionId != null ? tagDefinitionId.hashCode() : 0;
         result = 31 * result + (tagDefinition != null ? tagDefinition.hashCode() : 0);
         result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
         return result;
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDefinitionDeletionEvent.java b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDefinitionDeletionEvent.java
index 391a099..a324d49 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDefinitionDeletionEvent.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDefinitionDeletionEvent.java
@@ -18,23 +18,29 @@ package com.ning.billing.util.tag.api.user;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.UserTagDefinitionDeletionEvent;
 
 public class DefaultUserTagDefinitionDeletionEvent implements UserTagDefinitionDeletionEvent {
-    private final UUID tagId;
+    private final UUID tagDefinitionId;
     private final TagDefinition tagDefinition;
     private final UUID userToken;
 
-    public DefaultUserTagDefinitionDeletionEvent(final UUID tagDefinitionId, final TagDefinition tagDefinition, final UUID userToken) {
-        this.tagId = tagDefinitionId;
+    @JsonCreator
+    public DefaultUserTagDefinitionDeletionEvent(@JsonProperty("tagDefinitionId") final UUID tagDefinitionId,
+                                                 @JsonProperty("tagDefinition") final TagDefinition tagDefinition,
+                                                 @JsonProperty("userToken") final UUID userToken) {
+        this.tagDefinitionId = tagDefinitionId;
         this.tagDefinition = tagDefinition;
         this.userToken = userToken;
     }
 
     @Override
     public UUID getTagDefinitionId() {
-        return tagId;
+        return tagDefinitionId;
     }
 
     @Override
@@ -42,6 +48,7 @@ public class DefaultUserTagDefinitionDeletionEvent implements UserTagDefinitionD
         return tagDefinition;
     }
 
+    @JsonIgnore
     @Override
     public BusEventType getBusEventType() {
         return BusEventType.USER_TAGDEFINITION_DELETION;
@@ -57,7 +64,7 @@ public class DefaultUserTagDefinitionDeletionEvent implements UserTagDefinitionD
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultUserTagDefinitionDeletionEvent");
         sb.append("{tagDefinition=").append(tagDefinition);
-        sb.append(", tagId=").append(tagId);
+        sb.append(", tagDefinitionId=").append(tagDefinitionId);
         sb.append(", userToken=").append(userToken);
         sb.append('}');
         return sb.toString();
@@ -77,7 +84,7 @@ public class DefaultUserTagDefinitionDeletionEvent implements UserTagDefinitionD
         if (tagDefinition != null ? !tagDefinition.equals(that.tagDefinition) : that.tagDefinition != null) {
             return false;
         }
-        if (tagId != null ? !tagId.equals(that.tagId) : that.tagId != null) {
+        if (tagDefinitionId != null ? !tagDefinitionId.equals(that.tagDefinitionId) : that.tagDefinitionId != null) {
             return false;
         }
         if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
@@ -89,7 +96,7 @@ public class DefaultUserTagDefinitionDeletionEvent implements UserTagDefinitionD
 
     @Override
     public int hashCode() {
-        int result = tagId != null ? tagId.hashCode() : 0;
+        int result = tagDefinitionId != null ? tagDefinitionId.hashCode() : 0;
         result = 31 * result + (tagDefinition != null ? tagDefinition.hashCode() : 0);
         result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
         return result;
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDeletionEvent.java b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDeletionEvent.java
index d073740..a19f97b 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDeletionEvent.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/user/DefaultUserTagDeletionEvent.java
@@ -18,6 +18,9 @@ package com.ning.billing.util.tag.api.user;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.api.UserTagDeletionEvent;
@@ -29,7 +32,12 @@ public class DefaultUserTagDeletionEvent implements UserTagDeletionEvent {
     private final TagDefinition tagDefinition;
     private final UUID userToken;
 
-    public DefaultUserTagDeletionEvent(final UUID tagId, final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final UUID userToken) {
+    @JsonCreator
+    public DefaultUserTagDeletionEvent(@JsonProperty("tagId") final UUID tagId,
+                                       @JsonProperty("objectId") final UUID objectId,
+                                       @JsonProperty("objectType") final ObjectType objectType,
+                                       @JsonProperty("tagDefinition") final TagDefinition tagDefinition,
+                                       @JsonProperty("userToken") final UUID userToken) {
         this.tagId = tagId;
         this.objectId = objectId;
         this.objectType = objectType;
@@ -57,6 +65,7 @@ public class DefaultUserTagDeletionEvent implements UserTagDeletionEvent {
         return tagDefinition;
     }
 
+    @JsonIgnore
     @Override
     public BusEventType getBusEventType() {
         return BusEventType.USER_TAG_DELETION;
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 c34985f..67410ee 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,7 +16,6 @@
 
 package com.ning.billing.util.tag.dao;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -25,12 +24,16 @@ 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.google.inject.Inject;
 import com.ning.billing.ErrorCode;
-import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.api.TagApiException;
+import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.dao.AuditedCollectionDaoBase;
@@ -40,14 +43,14 @@ import com.ning.billing.util.dao.Mapper;
 import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
-import com.ning.billing.util.tag.ControlTagType;
-import com.ning.billing.util.tag.DefaultControlTag;
-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.TagEvent;
 import com.ning.billing.util.tag.api.user.TagEventBuilder;
 
 public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements TagDao {
+    private static final Logger log = LoggerFactory.getLogger(AuditedTagDao.class);
+
     private final TagSqlDao tagSqlDao;
     private final TagEventBuilder tagEventBuilder;
     private final Bus bus;
@@ -65,89 +68,107 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag, Tag> implements
     }
 
     @Override
-    public void insertTag(final UUID objectId, final ObjectType objectType,
-                          final TagDefinition tagDefinition, final CallContext context) {
+    public void insertTag(final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final CallContext context) {
         tagSqlDao.inTransaction(new Transaction<Void, TagSqlDao>() {
             @Override
             public Void inTransaction(final TagSqlDao tagSqlDao, final TransactionStatus status) throws Exception {
                 final String tagId = UUID.randomUUID().toString();
                 final String tagName = tagDefinition.getName();
+
+                // Create the tag
                 tagSqlDao.addTagFromTransaction(tagId, tagName, objectId.toString(), objectType, context);
 
                 final Tag tag = tagSqlDao.findTag(tagName, objectId.toString(), objectType);
-                final List<Tag> tagList = new ArrayList<Tag>();
-                tagList.add(tag);
+                final List<Tag> tagList = Arrays.asList(tag);
 
+                // Gather the tag ids for this object id
                 final List<Mapper<UUID, Long>> recordIds = tagSqlDao.getRecordIds(objectId.toString(), objectType);
                 final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
 
-                final List<EntityHistory<Tag>> entityHistories = new ArrayList<EntityHistory<Tag>>();
-                entityHistories.addAll(convertToHistory(tagList, recordIdMap, ChangeType.INSERT));
-
+                // Update the history table
+                final List<EntityHistory<Tag>> entityHistories = convertToHistory(tagList, recordIdMap, ChangeType.INSERT);
                 final Long maxHistoryRecordId = tagSqlDao.getMaxHistoryRecordId();
                 tagSqlDao.addHistoryFromTransaction(objectId.toString(), objectType, entityHistories, context);
 
-                // have to fetch history record ids to update audit log
+                // Have to fetch the history record ids to update the audit log
                 final List<Mapper<Long, Long>> historyRecordIds = tagSqlDao.getHistoryRecordIds(maxHistoryRecordId);
                 final Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
                 final List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
                 tagSqlDao.insertAuditFromTransaction(entityAudits, context);
 
+                // Post an event to the Bus
+                final TagEvent tagEvent;
+                if (tagDefinition.isControlTag()) {
+                    tagEvent = tagEventBuilder.newControlTagCreationEvent(tag.getId(), objectId, objectType, tagDefinition, context.getUserToken());
+                } else {
+                    tagEvent = tagEventBuilder.newUserTagCreationEvent(tag.getId(), objectId, objectType, tagDefinition, context.getUserToken());
+                }
+                try {
+                    bus.postFromTransaction(tagEvent, AuditedTagDao.this.tagSqlDao);
+                } catch (Bus.EventBusException e) {
+                    log.warn("Failed to post tag creation event for tag " + tag.getId().toString(), e);
+                }
+
                 return null;
             }
         });
     }
 
     @Override
-    public void insertTags(final UUID objectId, final ObjectType objectType, final List<TagDefinition> tagDefinitions, final CallContext context) {
-        final List<Tag> tags = new ArrayList<Tag>();
-        for (final TagDefinition tagDefinition : tagDefinitions) {
-            if (tagDefinition.isControlTag()) {
-                final ControlTagType controlTagType = ControlTagType.valueOf(tagDefinition.getName());
-                tags.add(new DefaultControlTag(controlTagType));
+    public void deleteTag(final UUID objectId, final ObjectType objectType, final TagDefinition tagDefinition, final CallContext context) throws TagApiException {
+        try {
+            tagSqlDao.inTransaction(new Transaction<Void, TagSqlDao>() {
+                @Override
+                public Void inTransaction(final TagSqlDao tagSqlDao, final TransactionStatus status) throws Exception {
+                    // Make sure the tag exists
+                    final String tagName = tagDefinition.getName();
+                    final Tag tag = tagSqlDao.findTag(tagName, objectId.toString(), objectType);
+                    if (tag == null) {
+                        throw new TagApiException(ErrorCode.TAG_DOES_NOT_EXIST, tagName);
+                    }
+
+                    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);
+                    final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
+
+                    // 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();
+                    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);
+                    final Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
+                    final List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
+                    tagSqlDao.insertAuditFromTransaction(entityAudits, context);
+
+                    // Post an event to the Bus
+                    final TagEvent tagEvent;
+                    if (tagDefinition.isControlTag()) {
+                        tagEvent = tagEventBuilder.newControlTagDeletionEvent(tag.getId(), objectId, objectType, tagDefinition, context.getUserToken());
+                    } else {
+                        tagEvent = tagEventBuilder.newUserTagDeletionEvent(tag.getId(), objectId, objectType, tagDefinition, context.getUserToken());
+                    }
+                    try {
+                        bus.postFromTransaction(tagEvent, tagSqlDao);
+                    } catch (Bus.EventBusException e) {
+                        log.warn("Failed to post tag deletion event for tag " + tag.getId().toString(), e);
+                    }
+                    return null;
+                }
+            });
+        } catch (TransactionFailedException exception) {
+            if (exception.getCause() instanceof TagDefinitionApiException) {
+                throw (TagApiException) exception.getCause();
             } else {
-                tags.add(new DescriptiveTag(tagDefinition));
+                throw exception;
             }
         }
-
-        saveEntities(objectId, objectType, tags, context);
-    }
-
-    @Override
-    public void deleteTag(final UUID objectId, final ObjectType objectType,
-                          final TagDefinition tagDefinition, final CallContext context) {
-        tagSqlDao.inTransaction(new Transaction<Void, TagSqlDao>() {
-            @Override
-            public Void inTransaction(final TagSqlDao tagSqlDao, final TransactionStatus status) throws Exception {
-                final String tagName = tagDefinition.getName();
-                final Tag tag = tagSqlDao.findTag(tagName, objectId.toString(), objectType);
-
-                if (tag == null) {
-                    throw new InvoiceApiException(ErrorCode.TAG_DOES_NOT_EXIST, tagName);
-                }
-
-                final List<Tag> tagList = Arrays.asList(tag);
-
-                final List<Mapper<UUID, Long>> recordIds = tagSqlDao.getRecordIds(objectId.toString(), objectType);
-                final Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
-
-                tagSqlDao.deleteFromTransaction(objectId.toString(), objectType, tagList, context);
-
-                final List<EntityHistory<Tag>> entityHistories = new ArrayList<EntityHistory<Tag>>();
-                entityHistories.addAll(convertToHistory(tagList, recordIdMap, ChangeType.DELETE));
-
-                final Long maxHistoryRecordId = tagSqlDao.getMaxHistoryRecordId();
-                tagSqlDao.addHistoryFromTransaction(objectId.toString(), objectType, entityHistories, context);
-
-                // have to fetch history record ids to update audit log
-                final List<Mapper<Long, Long>> historyRecordIds = tagSqlDao.getHistoryRecordIds(maxHistoryRecordId);
-                final Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
-                final List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
-                tagSqlDao.insertAuditFromTransaction(entityAudits, context);
-
-                return null;
-            }
-        });
     }
 
     @Override
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
index 049c42d..f7f25b7 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -23,6 +23,8 @@ 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
@@ -32,9 +34,12 @@ import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
+import com.ning.billing.util.tag.api.TagDefinitionEvent;
 import com.ning.billing.util.tag.api.user.TagEventBuilder;
 
 public class DefaultTagDefinitionDao implements TagDefinitionDao {
+    private static final Logger log = LoggerFactory.getLogger(DefaultTagDefinitionDao.class);
+
     private final TagDefinitionSqlDao tagDefinitionSqlDao;
     private final TagEventBuilder tagEventBuilder;
     private final Bus bus;
@@ -83,17 +88,31 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
         try {
             return tagDefinitionSqlDao.inTransaction(new Transaction<TagDefinition, TagDefinitionSqlDao>() {
                 @Override
-                public TagDefinition inTransaction(final TagDefinitionSqlDao transactional, final TransactionStatus status) throws Exception {
+                public TagDefinition inTransaction(final TagDefinitionSqlDao tagDefinitionSqlDao, final TransactionStatus status) throws Exception {
                     // Make sure the tag definition doesn't exist already
                     final TagDefinition existingDefinition = tagDefinitionSqlDao.getByName(definitionName);
                     if (existingDefinition != null) {
                         throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_ALREADY_EXISTS, definitionName);
                     }
 
-                    final TagDefinition definition = new DefaultTagDefinition(definitionName, description, false);
-                    tagDefinitionSqlDao.create(definition, context);
+                    // Create it
+                    final TagDefinition tagDefinition = new DefaultTagDefinition(definitionName, description, false);
+                    tagDefinitionSqlDao.create(tagDefinition, context);
+
+                    // Post an event to the bus
+                    final TagDefinitionEvent tagDefinitionEvent;
+                    if (tagDefinition.isControlTag()) {
+                        tagDefinitionEvent = tagEventBuilder.newControlTagDefinitionCreationEvent(tagDefinition.getId(), tagDefinition, context.getUserToken());
+                    } else {
+                        tagDefinitionEvent = tagEventBuilder.newUserTagDefinitionCreationEvent(tagDefinition.getId(), tagDefinition, context.getUserToken());
+                    }
+                    try {
+                        bus.postFromTransaction(tagDefinitionEvent, tagDefinitionSqlDao);
+                    } catch (Bus.EventBusException e) {
+                        log.warn("Failed to post tag definition creation event for tag " + tagDefinition.getId(), e);
+                    }
 
-                    return definition;
+                    return tagDefinition;
                 }
             });
         } catch (TransactionFailedException exception) {
@@ -120,10 +139,10 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
         try {
             tagDefinitionSqlDao.inTransaction(new Transaction<Void, TagDefinitionSqlDao>() {
                 @Override
-                public Void inTransaction(final TagDefinitionSqlDao transactional, final TransactionStatus status) throws Exception {
+                public Void inTransaction(final TagDefinitionSqlDao tagDefinitionSqlDao, final TransactionStatus status) throws Exception {
                     // Make sure the tag definition exists
-                    final TagDefinition existingDefinition = tagDefinitionSqlDao.getByName(definitionName);
-                    if (existingDefinition == null) {
+                    final TagDefinition tagDefinition = tagDefinitionSqlDao.getByName(definitionName);
+                    if (tagDefinition == null) {
                         throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_DOES_NOT_EXIST, definitionName);
                     }
 
@@ -132,8 +151,22 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
                         throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_IN_USE, definitionName);
                     }
 
+                    // Delete it
                     tagDefinitionSqlDao.deleteTagDefinition(definitionName, context);
 
+                    // Post an event to the Bus
+                    final TagDefinitionEvent tagDefinitionEvent;
+                    if (tagDefinition.isControlTag()) {
+                        tagDefinitionEvent = tagEventBuilder.newControlTagDefinitionDeletionEvent(tagDefinition.getId(), tagDefinition, context.getUserToken());
+                    } else {
+                        tagDefinitionEvent = tagEventBuilder.newUserTagDefinitionDeletionEvent(tagDefinition.getId(), tagDefinition, context.getUserToken());
+                    }
+                    try {
+                        bus.postFromTransaction(tagDefinitionEvent, tagDefinitionSqlDao);
+                    } catch (Bus.EventBusException e) {
+                        log.warn("Failed to post tag definition deletion event for tag " + tagDefinition.getId(), e);
+                    }
+
                     return null;
                 }
             });
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 db059ce..3ffccf2 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
@@ -19,6 +19,7 @@ package com.ning.billing.util.tag.dao;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.dao.AuditedCollectionDao;
 import com.ning.billing.util.dao.ObjectType;
@@ -26,9 +27,7 @@ import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.TagDefinition;
 
 public interface TagDao extends AuditedCollectionDao<Tag> {
-    void insertTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition, CallContext context);
+    void insertTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition, CallContext context) throws TagApiException;
 
-    void insertTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions, CallContext context);
-
-    void deleteTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition, CallContext context);
+    void deleteTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition, CallContext context) throws TagApiException;
 }
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 4a7dd1c..6dee4b8 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.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
@@ -46,7 +47,7 @@ import com.ning.billing.util.tag.TagDefinition;
 
 @ExternalizedSqlViaStringTemplate3
 @RegisterMapper(TagDefinitionSqlDao.TagDefinitionMapper.class)
-public interface TagDefinitionSqlDao extends EntitySqlDao<TagDefinition>, Transactional<TagDefinitionSqlDao> {
+public interface TagDefinitionSqlDao extends EntitySqlDao<TagDefinition>, Transactional<TagDefinitionSqlDao>, Transmogrifier {
     @Override
     @SqlUpdate
     public void create(@TagDefinitionBinder final TagDefinition entity, @CallContextBinder final CallContext context);
diff --git a/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java b/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
index 139a66c..f0e80ad 100644
--- a/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
+++ b/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
@@ -18,22 +18,28 @@ package com.ning.billing.util.tag;
 
 import java.util.UUID;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.util.entity.EntityBase;
 
 public class DefaultTagDefinition extends EntityBase implements TagDefinition {
     private final String name;
     private final String description;
-    private final Boolean isControlTag;
+    private final Boolean controlTag;
 
     public DefaultTagDefinition(final String name, final String description, final Boolean isControlTag) {
         this(UUID.randomUUID(), name, description, isControlTag);
     }
 
-    public DefaultTagDefinition(final UUID id, final String name, final String description, final Boolean isControlTag) {
+    @JsonCreator
+    public DefaultTagDefinition(@JsonProperty("id") final UUID id,
+                                @JsonProperty("name") final String name,
+                                @JsonProperty("description") final String description,
+                                @JsonProperty("controlTag") final Boolean controlTag) {
         super(id);
         this.name = name;
         this.description = description;
-        this.isControlTag = isControlTag;
+        this.controlTag = controlTag;
     }
 
     @Override
@@ -48,6 +54,49 @@ public class DefaultTagDefinition extends EntityBase implements TagDefinition {
 
     @Override
     public Boolean isControlTag() {
-        return isControlTag;
+        return controlTag;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("DefaultTagDefinition");
+        sb.append("{description='").append(description).append('\'');
+        sb.append(", name='").append(name).append('\'');
+        sb.append(", controlTag=").append(controlTag);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final DefaultTagDefinition that = (DefaultTagDefinition) o;
+
+        if (description != null ? !description.equals(that.description) : that.description != null) {
+            return false;
+        }
+        if (controlTag != null ? !controlTag.equals(that.controlTag) : that.controlTag != null) {
+            return false;
+        }
+        if (name != null ? !name.equals(that.name) : that.name != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (description != null ? description.hashCode() : 0);
+        result = 31 * result + (controlTag != null ? controlTag.hashCode() : 0);
+        return result;
     }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagCreationEvent.java b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagCreationEvent.java
index f8a594a..5ebd270 100644
--- a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagCreationEvent.java
+++ b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagCreationEvent.java
@@ -23,6 +23,7 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.util.bus.BusEvent;
 import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.jackson.ObjectMapper;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
@@ -56,4 +57,25 @@ public class TestDefaultControlTagCreationEvent {
         Assert.assertTrue(event.equals(event));
         Assert.assertTrue(event.equals(new DefaultControlTagCreationEvent(tagId, objectId, objectType, tagDefinition, userToken)));
     }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID tagId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.ACCOUNT_EMAIL;
+        final UUID tagDefinitionId = UUID.randomUUID();
+        final String tagDefinitionName = UUID.randomUUID().toString();
+        final String tagDefinitionDescription = UUID.randomUUID().toString();
+        final boolean controlTag = true;
+        final TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, tagDefinitionName, tagDefinitionDescription, controlTag);
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultControlTagCreationEvent event = new DefaultControlTagCreationEvent(tagId, objectId, objectType, tagDefinition, userToken);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultControlTagCreationEvent fromJson = objectMapper.readValue(json, DefaultControlTagCreationEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDefinitionCreationEvent.java b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDefinitionCreationEvent.java
index 7f2260b..05d4c05 100644
--- a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDefinitionCreationEvent.java
+++ b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDefinitionCreationEvent.java
@@ -22,6 +22,7 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.util.bus.BusEvent;
+import com.ning.billing.util.jackson.ObjectMapper;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
@@ -50,4 +51,22 @@ public class TestDefaultControlTagDefinitionCreationEvent {
         Assert.assertTrue(event.equals(event));
         Assert.assertTrue(event.equals(new DefaultControlTagDefinitionCreationEvent(tagDefinitionId, tagDefinition, userToken)));
     }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID tagDefinitionId = UUID.randomUUID();
+        final String tagDefinitionName = UUID.randomUUID().toString();
+        final String tagDefinitionDescription = UUID.randomUUID().toString();
+        final boolean controlTag = true;
+        final TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, tagDefinitionName, tagDefinitionDescription, controlTag);
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultControlTagDefinitionCreationEvent event = new DefaultControlTagDefinitionCreationEvent(tagDefinitionId, tagDefinition, userToken);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultControlTagDefinitionCreationEvent fromJson = objectMapper.readValue(json, DefaultControlTagDefinitionCreationEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDefinitionDeletionEvent.java b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDefinitionDeletionEvent.java
index 26d2322..08059d1 100644
--- a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDefinitionDeletionEvent.java
+++ b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDefinitionDeletionEvent.java
@@ -22,6 +22,7 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.util.bus.BusEvent;
+import com.ning.billing.util.jackson.ObjectMapper;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
@@ -50,4 +51,22 @@ public class TestDefaultControlTagDefinitionDeletionEvent {
         Assert.assertTrue(event.equals(event));
         Assert.assertTrue(event.equals(new DefaultControlTagDefinitionDeletionEvent(tagDefinitionId, tagDefinition, userToken)));
     }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID tagDefinitionId = UUID.randomUUID();
+        final String tagDefinitionName = UUID.randomUUID().toString();
+        final String tagDefinitionDescription = UUID.randomUUID().toString();
+        final boolean controlTag = true;
+        final TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, tagDefinitionName, tagDefinitionDescription, controlTag);
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultControlTagDefinitionDeletionEvent event = new DefaultControlTagDefinitionDeletionEvent(tagDefinitionId, tagDefinition, userToken);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultControlTagDefinitionDeletionEvent fromJson = objectMapper.readValue(json, DefaultControlTagDefinitionDeletionEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDeletionEvent.java b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDeletionEvent.java
index 089ee63..692149a 100644
--- a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDeletionEvent.java
+++ b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultControlTagDeletionEvent.java
@@ -23,6 +23,7 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.util.bus.BusEvent;
 import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.jackson.ObjectMapper;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
@@ -56,4 +57,25 @@ public class TestDefaultControlTagDeletionEvent {
         Assert.assertTrue(event.equals(event));
         Assert.assertTrue(event.equals(new DefaultControlTagDeletionEvent(tagId, objectId, objectType, tagDefinition, userToken)));
     }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID tagId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.ACCOUNT_EMAIL;
+        final UUID tagDefinitionId = UUID.randomUUID();
+        final String tagDefinitionName = UUID.randomUUID().toString();
+        final String tagDefinitionDescription = UUID.randomUUID().toString();
+        final boolean controlTag = true;
+        final TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, tagDefinitionName, tagDefinitionDescription, controlTag);
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultControlTagDeletionEvent event = new DefaultControlTagDeletionEvent(tagId, objectId, objectType, tagDefinition, userToken);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultControlTagDeletionEvent fromJson = objectMapper.readValue(json, DefaultControlTagDeletionEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagCreationEvent.java b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagCreationEvent.java
index 72e5f98..4d8162a 100644
--- a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagCreationEvent.java
+++ b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagCreationEvent.java
@@ -23,6 +23,7 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.util.bus.BusEvent;
 import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.jackson.ObjectMapper;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
@@ -56,4 +57,25 @@ public class TestDefaultUserTagCreationEvent {
         Assert.assertTrue(event.equals(event));
         Assert.assertTrue(event.equals(new DefaultUserTagCreationEvent(tagId, objectId, objectType, tagDefinition, userToken)));
     }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID tagId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.ACCOUNT_EMAIL;
+        final UUID tagDefinitionId = UUID.randomUUID();
+        final String tagDefinitionName = UUID.randomUUID().toString();
+        final String tagDefinitionDescription = UUID.randomUUID().toString();
+        final boolean controlTag = true;
+        final TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, tagDefinitionName, tagDefinitionDescription, controlTag);
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultUserTagCreationEvent event = new DefaultUserTagCreationEvent(tagId, objectId, objectType, tagDefinition, userToken);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultUserTagCreationEvent fromJson = objectMapper.readValue(json, DefaultUserTagCreationEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDefinitionCreationEvent.java b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDefinitionCreationEvent.java
index 9c033b9..89507d3 100644
--- a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDefinitionCreationEvent.java
+++ b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDefinitionCreationEvent.java
@@ -22,6 +22,7 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.util.bus.BusEvent;
+import com.ning.billing.util.jackson.ObjectMapper;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
@@ -50,4 +51,22 @@ public class TestDefaultUserTagDefinitionCreationEvent {
         Assert.assertTrue(event.equals(event));
         Assert.assertTrue(event.equals(new DefaultUserTagDefinitionCreationEvent(tagDefinitionId, tagDefinition, userToken)));
     }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID tagDefinitionId = UUID.randomUUID();
+        final String tagDefinitionName = UUID.randomUUID().toString();
+        final String tagDefinitionDescription = UUID.randomUUID().toString();
+        final boolean controlTag = true;
+        final TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, tagDefinitionName, tagDefinitionDescription, controlTag);
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultUserTagDefinitionCreationEvent event = new DefaultUserTagDefinitionCreationEvent(tagDefinitionId, tagDefinition, userToken);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultUserTagDefinitionCreationEvent fromJson = objectMapper.readValue(json, DefaultUserTagDefinitionCreationEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDefinitionDeletionEvent.java b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDefinitionDeletionEvent.java
index b5f7615..bdcfaff 100644
--- a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDefinitionDeletionEvent.java
+++ b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDefinitionDeletionEvent.java
@@ -22,6 +22,7 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.util.bus.BusEvent;
+import com.ning.billing.util.jackson.ObjectMapper;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
@@ -50,4 +51,22 @@ public class TestDefaultUserTagDefinitionDeletionEvent {
         Assert.assertTrue(event.equals(event));
         Assert.assertTrue(event.equals(new DefaultUserTagDefinitionDeletionEvent(tagDefinitionId, tagDefinition, userToken)));
     }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID tagDefinitionId = UUID.randomUUID();
+        final String tagDefinitionName = UUID.randomUUID().toString();
+        final String tagDefinitionDescription = UUID.randomUUID().toString();
+        final boolean controlTag = true;
+        final TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, tagDefinitionName, tagDefinitionDescription, controlTag);
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultUserTagDefinitionDeletionEvent event = new DefaultUserTagDefinitionDeletionEvent(tagDefinitionId, tagDefinition, userToken);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultUserTagDefinitionDeletionEvent fromJson = objectMapper.readValue(json, DefaultUserTagDefinitionDeletionEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDeletionEvent.java b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDeletionEvent.java
index ed5b073..ff022ef 100644
--- a/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDeletionEvent.java
+++ b/util/src/test/java/com/ning/billing/util/tag/api/user/TestDefaultUserTagDeletionEvent.java
@@ -23,6 +23,7 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.util.bus.BusEvent;
 import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.jackson.ObjectMapper;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
 
@@ -56,4 +57,25 @@ public class TestDefaultUserTagDeletionEvent {
         Assert.assertTrue(event.equals(event));
         Assert.assertTrue(event.equals(new DefaultUserTagDeletionEvent(tagId, objectId, objectType, tagDefinition, userToken)));
     }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID tagId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.ACCOUNT_EMAIL;
+        final UUID tagDefinitionId = UUID.randomUUID();
+        final String tagDefinitionName = UUID.randomUUID().toString();
+        final String tagDefinitionDescription = UUID.randomUUID().toString();
+        final boolean controlTag = true;
+        final TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, tagDefinitionName, tagDefinitionDescription, controlTag);
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultUserTagDeletionEvent event = new DefaultUserTagDeletionEvent(tagId, objectId, objectType, tagDefinition, userToken);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultUserTagDeletionEvent fromJson = objectMapper.readValue(json, DefaultUserTagDeletionEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
 }
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 09e757d..a09a952 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
@@ -90,14 +90,6 @@ public class MockTagDao implements TagDao {
     }
 
     @Override
-    public void insertTags(final UUID objectId, final ObjectType objectType,
-                           final List<TagDefinition> tagDefinitions, final CallContext context) {
-        for (final TagDefinition tagDefinition : tagDefinitions) {
-            insertTag(objectId, objectType, tagDefinition, context);
-        }
-    }
-
-    @Override
     public void deleteTag(final UUID objectId, final ObjectType objectType,
                           final TagDefinition tagDefinition, final CallContext context) {
         final List<Tag> tags = tagStore.get(objectId);
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
new file mode 100644
index 0000000..e986950
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
@@ -0,0 +1,170 @@
+/*
+ * 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.tag.dao;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.commons.io.IOUtils;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.BusEvent;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.tag.MockTagStoreModuleSql;
+import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.TagDefinition;
+import com.ning.billing.util.tag.TestTagStore;
+import com.ning.billing.util.tag.api.TagEvent;
+
+@Guice(modules = MockTagStoreModuleSql.class)
+public class TestAuditedTagDao {
+    @Inject
+    private MysqlTestingHelper helper;
+
+    @Inject
+    private TagDefinitionDao tagDefinitionDao;
+
+    @Inject
+    private AuditedTagDao tagDao;
+
+    @Inject
+    private Clock clock;
+
+    @Inject
+    private Bus bus;
+
+    private CallContext context;
+    private EventsListener eventsListener;
+
+    @BeforeClass(groups = "slow")
+    public void setup() throws IOException {
+        final String utilDdl = IOUtils.toString(TestTagStore.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
+
+        helper.startMysql();
+        helper.initDb(utilDdl);
+
+        context = new DefaultCallContextFactory(clock).createCallContext("Tag DAO test", CallOrigin.TEST, UserType.TEST, UUID.randomUUID());
+        bus.start();
+    }
+
+    @BeforeMethod(groups = "slow")
+    public void cleanup() throws Bus.EventBusException {
+        eventsListener = new EventsListener();
+        bus.register(eventsListener);
+    }
+
+    @AfterClass(groups = "slow")
+    public void stopMysql() {
+        bus.stop();
+        helper.stopMysql();
+    }
+
+    @Test(groups = "slow")
+    public void testCatchEventsOnCreateAndDelete() throws Exception {
+        final String definitionName = UUID.randomUUID().toString().substring(0, 5);
+        final String description = UUID.randomUUID().toString().substring(0, 5);
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.RECURRING_INVOICE_ITEM;
+
+        // Verify the initial state
+        Assert.assertEquals(eventsListener.getEvents().size(), 0);
+        Assert.assertEquals(eventsListener.getTagEvents().size(), 0);
+
+        // Create a tag definition
+        final TagDefinition createdTagDefinition = tagDefinitionDao.create(definitionName, description, context);
+        Assert.assertEquals(createdTagDefinition.getName(), definitionName);
+        Assert.assertEquals(createdTagDefinition.getDescription(), description);
+
+        // Make sure we can create a tag
+        tagDao.insertTag(objectId, objectType, createdTagDefinition, context);
+
+        // Make sure we can retrieve it via the DAO
+        final Map<String, Tag> foundTags = tagDao.loadEntities(objectId, objectType);
+        Assert.assertEquals(foundTags.keySet().size(), 1);
+        Assert.assertEquals(foundTags.get(definitionName).getTagDefinitionName(), definitionName);
+
+        // Verify we caught an event on the bus -  we got 2 total (one for the tag definition, one for the tag)
+        Assert.assertEquals(eventsListener.getEvents().size(), 2);
+        Assert.assertEquals(eventsListener.getTagEvents().size(), 1);
+        final TagEvent tagFirstEventReceived = eventsListener.getTagEvents().get(0);
+        Assert.assertEquals(eventsListener.getEvents().get(1), tagFirstEventReceived);
+        Assert.assertEquals(tagFirstEventReceived.getObjectId(), objectId);
+        Assert.assertEquals(tagFirstEventReceived.getObjectType(), objectType);
+        Assert.assertEquals(tagFirstEventReceived.getTagDefinition().getName(), createdTagDefinition.getName());
+        Assert.assertEquals(tagFirstEventReceived.getTagDefinition().getDescription(), createdTagDefinition.getDescription());
+        Assert.assertEquals(tagFirstEventReceived.getBusEventType(), BusEvent.BusEventType.USER_TAG_CREATION);
+        Assert.assertEquals(tagFirstEventReceived.getUserToken(), context.getUserToken());
+
+        // Delete the tag
+        tagDao.deleteTag(objectId, objectType, createdTagDefinition, context);
+
+        // Make sure the tag is deleted
+        Assert.assertEquals(tagDao.loadEntities(objectId, objectType).keySet().size(), 0);
+
+        // Verify we caught an event on the bus
+        Assert.assertEquals(eventsListener.getEvents().size(), 3);
+        Assert.assertEquals(eventsListener.getTagEvents().size(), 2);
+        final TagEvent tagSecondEventReceived = eventsListener.getTagEvents().get(1);
+        Assert.assertEquals(eventsListener.getEvents().get(2), tagSecondEventReceived);
+        Assert.assertEquals(tagSecondEventReceived.getObjectId(), objectId);
+        Assert.assertEquals(tagSecondEventReceived.getObjectType(), objectType);
+        Assert.assertEquals(tagSecondEventReceived.getTagDefinition().getName(), createdTagDefinition.getName());
+        Assert.assertEquals(tagSecondEventReceived.getTagDefinition().getDescription(), createdTagDefinition.getDescription());
+        Assert.assertEquals(tagSecondEventReceived.getBusEventType(), BusEvent.BusEventType.USER_TAG_DELETION);
+        Assert.assertEquals(tagSecondEventReceived.getUserToken(), context.getUserToken());
+    }
+
+    private static final class EventsListener {
+        private final List<BusEvent> events = new ArrayList<BusEvent>();
+        private final List<TagEvent> tagEvents = new ArrayList<TagEvent>();
+
+        @Subscribe
+        public synchronized void processEvent(final BusEvent event) {
+            events.add(event);
+        }
+
+        @Subscribe
+        public synchronized void processTagDefinitionEvent(final TagEvent tagEvent) {
+            tagEvents.add(tagEvent);
+        }
+
+        public List<BusEvent> getEvents() {
+            return events;
+        }
+
+        public List<TagEvent> getTagEvents() {
+            return tagEvents;
+        }
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDefinitionDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDefinitionDao.java
new file mode 100644
index 0000000..cc74c55
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDefinitionDao.java
@@ -0,0 +1,154 @@
+/*
+ * 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.tag.dao;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.commons.io.IOUtils;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.BusEvent;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.tag.MockTagStoreModuleSql;
+import com.ning.billing.util.tag.TagDefinition;
+import com.ning.billing.util.tag.TestTagStore;
+import com.ning.billing.util.tag.api.TagDefinitionEvent;
+
+@Guice(modules = MockTagStoreModuleSql.class)
+public class TestDefaultTagDefinitionDao {
+    @Inject
+    private MysqlTestingHelper helper;
+
+    @Inject
+    private TagDefinitionDao tagDefinitionDao;
+
+    @Inject
+    private Clock clock;
+
+    @Inject
+    private Bus bus;
+
+    private CallContext context;
+    private EventsListener eventsListener;
+
+    @BeforeClass(groups = "slow")
+    public void setup() throws IOException {
+        final String utilDdl = IOUtils.toString(TestTagStore.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
+
+        helper.startMysql();
+        helper.initDb(utilDdl);
+
+        context = new DefaultCallContextFactory(clock).createCallContext("TagDefinition DAO test", CallOrigin.TEST, UserType.TEST, UUID.randomUUID());
+        bus.start();
+    }
+
+    @BeforeMethod(groups = "slow")
+    public void cleanup() throws Bus.EventBusException {
+        eventsListener = new EventsListener();
+        bus.register(eventsListener);
+    }
+
+    @AfterClass(groups = "slow")
+    public void stopMysql() {
+        bus.stop();
+        helper.stopMysql();
+    }
+
+    @Test(groups = "slow")
+    public void testCatchEventsOnCreateAndDelete() throws Exception {
+        final String definitionName = UUID.randomUUID().toString().substring(0, 5);
+        final String description = UUID.randomUUID().toString().substring(0, 5);
+
+        // Verify the initial state
+        Assert.assertEquals(eventsListener.getEvents().size(), 0);
+        Assert.assertEquals(eventsListener.getTagDefinitionEvents().size(), 0);
+
+        // Make sure we can create a tag definition
+        final TagDefinition createdTagDefinition = tagDefinitionDao.create(definitionName, description, context);
+        Assert.assertEquals(createdTagDefinition.getName(), definitionName);
+        Assert.assertEquals(createdTagDefinition.getDescription(), description);
+
+        // Make sure we can retrieve it via the DAO
+        final TagDefinition foundTagDefinition = tagDefinitionDao.getByName(definitionName);
+        Assert.assertEquals(foundTagDefinition, createdTagDefinition);
+
+        // Verify we caught an event on the bus
+        Assert.assertEquals(eventsListener.getEvents().size(), 1);
+        Assert.assertEquals(eventsListener.getTagDefinitionEvents().size(), 1);
+        final TagDefinitionEvent tagDefinitionFirstEventReceived = eventsListener.getTagDefinitionEvents().get(0);
+        Assert.assertEquals(eventsListener.getEvents().get(0), tagDefinitionFirstEventReceived);
+        Assert.assertEquals(tagDefinitionFirstEventReceived.getTagDefinitionId(), createdTagDefinition.getId());
+        Assert.assertEquals(tagDefinitionFirstEventReceived.getTagDefinition(), createdTagDefinition);
+        Assert.assertEquals(tagDefinitionFirstEventReceived.getBusEventType(), BusEvent.BusEventType.USER_TAGDEFINITION_CREATION);
+        Assert.assertEquals(tagDefinitionFirstEventReceived.getUserToken(), context.getUserToken());
+
+        // Delete the tag definition
+        tagDefinitionDao.deleteTagDefinition(definitionName, context);
+
+        // Make sure the tag definition is deleted
+        Assert.assertNull(tagDefinitionDao.getByName(definitionName));
+
+        // Verify we caught an event on the bus
+        Assert.assertEquals(eventsListener.getEvents().size(), 2);
+        Assert.assertEquals(eventsListener.getTagDefinitionEvents().size(), 2);
+        final TagDefinitionEvent tagDefinitionSecondEventReceived = eventsListener.getTagDefinitionEvents().get(1);
+        Assert.assertEquals(eventsListener.getEvents().get(1), tagDefinitionSecondEventReceived);
+        Assert.assertEquals(tagDefinitionSecondEventReceived.getTagDefinitionId(), createdTagDefinition.getId());
+        Assert.assertEquals(tagDefinitionSecondEventReceived.getTagDefinition(), createdTagDefinition);
+        Assert.assertEquals(tagDefinitionSecondEventReceived.getBusEventType(), BusEvent.BusEventType.USER_TAGDEFINITION_DELETION);
+        Assert.assertEquals(tagDefinitionSecondEventReceived.getUserToken(), context.getUserToken());
+    }
+
+    private static final class EventsListener {
+        private final List<BusEvent> events = new ArrayList<BusEvent>();
+        private final List<TagDefinitionEvent> tagDefinitionEvents = new ArrayList<TagDefinitionEvent>();
+
+        @Subscribe
+        public synchronized void processEvent(final BusEvent event) {
+            events.add(event);
+        }
+
+        @Subscribe
+        public synchronized void processTagDefinitionEvent(final TagDefinitionEvent tagDefinitionEvent) {
+            tagDefinitionEvents.add(tagDefinitionEvent);
+        }
+
+        public List<BusEvent> getEvents() {
+            return events;
+        }
+
+        public List<TagDefinitionEvent> getTagDefinitionEvents() {
+            return tagDefinitionEvents;
+        }
+    }
+}
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 8dcd638..69187ae 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
@@ -37,7 +37,7 @@ import org.testng.annotations.Test;
 
 import com.google.inject.Inject;
 import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.callcontext.CallContext;
@@ -285,7 +285,7 @@ public class TestTagStore {
     }
 
     @Test(groups = "slow")
-    public void testDeleteTagBeforeDeleteTagDefinition() {
+    public void testDeleteTagBeforeDeleteTagDefinition() throws TagApiException {
         final String definitionName = "TestTag1234567";
         try {
             tagDefinitionDao.create(definitionName, "Some test tag", context);
@@ -342,7 +342,7 @@ public class TestTagStore {
 
         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());
+                                           tag.getId().toString());
         final List<Map<String, Object>> result = handle.select(query);
         handle.close();
 
@@ -373,7 +373,7 @@ public class TestTagStore {
 
         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());
+                                           tag.getId().toString());
         final List<Map<String, Object>> result = handle.select(query);
         handle.close();
 
@@ -386,7 +386,7 @@ public class TestTagStore {
     }
 
     @Test
-    public void testAddTag() {
+    public void testAddTag() throws TagApiException {
         final UUID objectId = UUID.randomUUID();
         final ObjectType objectType = ObjectType.INVOICE;
         final TagDefinition tagDefinition = new DefaultTagDefinition("test tag", "test", false);
@@ -396,7 +396,7 @@ public class TestTagStore {
     }
 
     @Test
-    public void testRemoveTag() throws InvoiceApiException {
+    public void testRemoveTag() throws TagApiException {
         final UUID objectId = UUID.randomUUID();
         final ObjectType objectType = ObjectType.INVOICE;
         final TagDefinition tagDefinition = new DefaultTagDefinition("test tag", "test", false);