killbill-aplcache

Changes

Details

diff --git a/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java b/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java
new file mode 100644
index 0000000..1770335
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java
@@ -0,0 +1,35 @@
+/*
+ * 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 java.util.List;
+import java.util.UUID;
+
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.dao.ObjectType;
+
+public interface AuditUserApi {
+
+    /**
+     * Get all the audit entries for a given object
+     *
+     * @param objectId   the object id
+     * @param objectType the type of object
+     * @return all audit entries for that object
+     */
+    public List<AuditLog> getAuditLogs(final UUID objectId, final ObjectType objectType);
+}
diff --git a/api/src/main/java/com/ning/billing/util/audit/AuditLog.java b/api/src/main/java/com/ning/billing/util/audit/AuditLog.java
new file mode 100644
index 0000000..be89e7f
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/audit/AuditLog.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.audit;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.ChangeType;
+
+public interface AuditLog {
+
+    /**
+     * Get the type of change for this log entry
+     *
+     * @return the ChangeType
+     */
+    public ChangeType getChangeType();
+
+    /**
+     * Get the name of the requestor
+     *
+     * @return the requestor user name
+     */
+    public String getUserName();
+
+    /**
+     * Get the time when this change was effective
+     *
+     * @return the created date of this log entry
+     */
+    public DateTime getCreatedDate();
+
+    /**
+     * Get the reason code for this change
+     *
+     * @return the reason code
+     */
+    public String getReasonCode();
+
+    /**
+     * Get the user token of this change requestor
+     *
+     * @return the user token
+     */
+    public String getUserToken();
+
+    /**
+     * Get the comment for this change
+     *
+     * @return the comment
+     */
+    public String getComment();
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AuditLogJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AuditLogJson.java
new file mode 100644
index 0000000..333a7d4
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AuditLogJson.java
@@ -0,0 +1,136 @@
+/*
+ * 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.jaxrs.json;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.audit.AuditLog;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class AuditLogJson {
+
+    private final String changeType;
+    private final DateTime changeDate;
+    private final String changedBy;
+    private final String reasonCode;
+    private final String comments;
+    private final String userToken;
+
+    @JsonCreator
+    public AuditLogJson(@JsonProperty("changeType") final String changeType,
+                        @JsonProperty("changeDate") final DateTime changeDate,
+                        @JsonProperty("changedBy") final String changedBy,
+                        @JsonProperty("reasonCode") final String reasonCode,
+                        @JsonProperty("comments") final String comments,
+                        @JsonProperty("userToken") final String userToken) {
+        this.changeType = changeType;
+        this.changeDate = changeDate;
+        this.changedBy = changedBy;
+        this.reasonCode = reasonCode;
+        this.comments = comments;
+        this.userToken = userToken;
+    }
+
+    public AuditLogJson(final AuditLog auditLog) {
+        this(auditLog.getChangeType().toString(), auditLog.getCreatedDate(), auditLog.getUserName(), auditLog.getReasonCode(),
+             auditLog.getComment(), auditLog.getUserToken());
+    }
+
+    public String getChangeType() {
+        return changeType;
+    }
+
+    public DateTime getChangeDate() {
+        return changeDate;
+    }
+
+    public String getChangedBy() {
+        return changedBy;
+    }
+
+    public String getReasonCode() {
+        return reasonCode;
+    }
+
+    public String getComments() {
+        return comments;
+    }
+
+    public String getUserToken() {
+        return userToken;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("AuditLogJson");
+        sb.append("{changeType='").append(changeType).append('\'');
+        sb.append(", changeDate=").append(changeDate);
+        sb.append(", changedBy=").append(changedBy);
+        sb.append(", reasonCode='").append(reasonCode).append('\'');
+        sb.append(", comments='").append(comments).append('\'');
+        sb.append(", userToken='").append(userToken).append('\'');
+        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 AuditLogJson that = (AuditLogJson) o;
+
+        if (changeDate != null ? changeDate.compareTo(that.changeDate) != 0 : that.changeDate != null) {
+            return false;
+        }
+        if (changeType != null ? !changeType.equals(that.changeType) : that.changeType != null) {
+            return false;
+        }
+        if (changedBy != null ? !changedBy.equals(that.changedBy) : that.changedBy != null) {
+            return false;
+        }
+        if (comments != null ? !comments.equals(that.comments) : that.comments != null) {
+            return false;
+        }
+        if (reasonCode != null ? !reasonCode.equals(that.reasonCode) : that.reasonCode != null) {
+            return false;
+        }
+        if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = changeType != null ? changeType.hashCode() : 0;
+        result = 31 * result + (changeDate != null ? changeDate.hashCode() : 0);
+        result = 31 * result + (changedBy != null ? changedBy.hashCode() : 0);
+        result = 31 * result + (reasonCode != null ? reasonCode.hashCode() : 0);
+        result = 31 * result + (comments != null ? comments.hashCode() : 0);
+        result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestAuditLogJson.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestAuditLogJson.java
new file mode 100644
index 0000000..3c7e31c
--- /dev/null
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestAuditLogJson.java
@@ -0,0 +1,107 @@
+/*
+ * 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.jaxrs.json;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.jaxrs.JaxrsTestSuite;
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.audit.DefaultAuditLog;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContext;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.clock.DefaultClock;
+import com.ning.billing.util.dao.EntityAudit;
+import com.ning.billing.util.dao.TableName;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.joda.JodaModule;
+
+public class TestAuditLogJson extends JaxrsTestSuite {
+
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    private final Clock clock = new DefaultClock();
+
+    static {
+        mapper.registerModule(new JodaModule());
+        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+    }
+
+    @Test(groups = "fast")
+    public void testJson() throws Exception {
+        final String changeType = UUID.randomUUID().toString();
+        final DateTime changeDate = clock.getUTCNow();
+        final String changedBy = UUID.randomUUID().toString();
+        final String reasonCode = UUID.randomUUID().toString();
+        final String comments = UUID.randomUUID().toString();
+        final String userToken = UUID.randomUUID().toString();
+
+        final AuditLogJson auditLogJson = new AuditLogJson(changeType, changeDate, changedBy, reasonCode, comments, userToken);
+        Assert.assertEquals(auditLogJson.getChangeType(), changeType);
+        Assert.assertEquals(auditLogJson.getChangeDate(), changeDate);
+        Assert.assertEquals(auditLogJson.getChangedBy(), changedBy);
+        Assert.assertEquals(auditLogJson.getReasonCode(), reasonCode);
+        Assert.assertEquals(auditLogJson.getComments(), comments);
+        Assert.assertEquals(auditLogJson.getUserToken(), userToken);
+
+        final String asJson = mapper.writeValueAsString(auditLogJson);
+        Assert.assertEquals(asJson, "{\"changeType\":\"" + auditLogJson.getChangeType() + "\"," +
+                                    "\"changeDate\":\"" + auditLogJson.getChangeDate().toDateTimeISO().toString() + "\"," +
+                                    "\"changedBy\":\"" + auditLogJson.getChangedBy() + "\"," +
+                                    "\"reasonCode\":\"" + auditLogJson.getReasonCode() + "\"," +
+                                    "\"comments\":\"" + auditLogJson.getComments() + "\"," +
+                                    "\"userToken\":\"" + auditLogJson.getUserToken() + "\"}");
+
+        final AuditLogJson fromJson = mapper.readValue(asJson, AuditLogJson.class);
+        Assert.assertEquals(fromJson, auditLogJson);
+    }
+
+    @Test(groups = "fast")
+    public void testConstructor() throws Exception {
+        final TableName tableName = TableName.ACCOUNT_EMAIL_HISTORY;
+        final long recordId = Long.MAX_VALUE;
+        final ChangeType changeType = ChangeType.DELETE;
+        final EntityAudit entityAudit = new EntityAudit(tableName, recordId, changeType);
+
+        final String userName = UUID.randomUUID().toString();
+        final CallOrigin callOrigin = CallOrigin.EXTERNAL;
+        final UserType userType = UserType.CUSTOMER;
+        final UUID userToken = UUID.randomUUID();
+        final ClockMock clock = new ClockMock();
+        final CallContext callContext = new DefaultCallContext(userName, callOrigin, userType, userToken, clock);
+
+        final AuditLog auditLog = new DefaultAuditLog(entityAudit, callContext);
+
+        final AuditLogJson auditLogJson = new AuditLogJson(auditLog);
+        Assert.assertEquals(auditLogJson.getChangeType(), changeType.toString());
+        Assert.assertNotNull(auditLogJson.getChangeDate());
+        Assert.assertEquals(auditLogJson.getChangedBy(), userName);
+        Assert.assertNull(auditLogJson.getReasonCode());
+        Assert.assertNull(auditLogJson.getComments());
+        Assert.assertEquals(auditLogJson.getUserToken(), userToken.toString());
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java b/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
new file mode 100644
index 0000000..6af61ea
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
@@ -0,0 +1,60 @@
+/*
+ * 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.audit.api;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import com.ning.billing.util.api.AuditUserApi;
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.audit.dao.AuditDao;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.TableName;
+
+import com.google.common.collect.ImmutableList;
+
+public class DefaultAuditUserApi implements AuditUserApi {
+
+    private final AuditDao auditDao;
+
+    @Inject
+    public DefaultAuditUserApi(final AuditDao auditDao) {
+        this.auditDao = auditDao;
+    }
+
+    @Override
+    public List<AuditLog> getAuditLogs(final UUID objectId, final ObjectType objectType) {
+        final TableName tableName = getTableNameFromObjectType(objectType);
+        if (tableName == null) {
+            return ImmutableList.<AuditLog>of();
+        }
+
+        return auditDao.getAuditLogsForRecordId(tableName, objectId);
+    }
+
+    private TableName getTableNameFromObjectType(final ObjectType objectType) {
+        for (final TableName tableName : TableName.values()) {
+            if (objectType.equals(tableName.getObjectType())) {
+                return tableName;
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/audit/dao/AuditDao.java b/util/src/main/java/com/ning/billing/util/audit/dao/AuditDao.java
new file mode 100644
index 0000000..224b78b
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/audit/dao/AuditDao.java
@@ -0,0 +1,28 @@
+/*
+ * 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.audit.dao;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.dao.TableName;
+
+public interface AuditDao {
+
+    public List<AuditLog> getAuditLogsForRecordId(final TableName tableName, final UUID objectId);
+}
diff --git a/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java b/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
new file mode 100644
index 0000000..7f38dee
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
@@ -0,0 +1,50 @@
+/*
+ * 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.audit.dao;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.dao.AuditSqlDao;
+import com.ning.billing.util.dao.TableName;
+
+import com.google.common.collect.ImmutableList;
+
+public class DefaultAuditDao implements AuditDao {
+
+    private final AuditSqlDao auditSqlDao;
+
+    @Inject
+    public DefaultAuditDao(final IDBI dbi) {
+        this.auditSqlDao = dbi.onDemand(AuditSqlDao.class);
+    }
+
+    @Override
+    public List<AuditLog> getAuditLogsForRecordId(final TableName tableName, final UUID objectId) {
+        final Long recordId = auditSqlDao.getRecordIdForTable(tableName, objectId.toString());
+        if (recordId == null) {
+            return ImmutableList.<AuditLog>of();
+        } else {
+            return auditSqlDao.getAuditLogsForRecordId(tableName, recordId);
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/audit/DefaultAuditLog.java b/util/src/main/java/com/ning/billing/util/audit/DefaultAuditLog.java
new file mode 100644
index 0000000..513697e
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/audit/DefaultAuditLog.java
@@ -0,0 +1,106 @@
+/*
+ * 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.audit;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.dao.EntityAudit;
+
+public class DefaultAuditLog implements AuditLog {
+
+    private final EntityAudit entityAudit;
+    private final CallContext callContext;
+
+    public DefaultAuditLog(final EntityAudit entityAudit, final CallContext callContext) {
+        this.entityAudit = entityAudit;
+        this.callContext = callContext;
+    }
+
+    @Override
+    public ChangeType getChangeType() {
+        return entityAudit.getChangeType();
+    }
+
+    @Override
+    public String getUserName() {
+        return callContext.getUserName();
+    }
+
+    @Override
+    public DateTime getCreatedDate() {
+        return callContext.getCreatedDate();
+    }
+
+    @Override
+    public String getReasonCode() {
+        return callContext.getReasonCode();
+    }
+
+    @Override
+    public String getUserToken() {
+        if (callContext.getUserToken() == null) {
+            return null;
+        } else {
+            return callContext.getUserToken().toString();
+        }
+    }
+
+    @Override
+    public String getComment() {
+        return callContext.getComment();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("DefaultAuditLog");
+        sb.append("{entityAudit=").append(entityAudit);
+        sb.append(", callContext=").append(callContext);
+        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 DefaultAuditLog that = (DefaultAuditLog) o;
+
+        if (callContext != null ? !callContext.equals(that.callContext) : that.callContext != null) {
+            return false;
+        }
+        if (entityAudit != null ? !entityAudit.equals(that.entityAudit) : that.entityAudit != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = entityAudit != null ? entityAudit.hashCode() : 0;
+        result = 31 * result + (callContext != null ? callContext.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/CallContextBase.java b/util/src/main/java/com/ning/billing/util/callcontext/CallContextBase.java
index 40d7ef5..2c21d05 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/CallContextBase.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/CallContextBase.java
@@ -19,12 +19,13 @@ package com.ning.billing.util.callcontext;
 import java.util.UUID;
 
 public abstract class CallContextBase implements CallContext {
-    private final UUID userToken;
-    private final String userName;
-    private final CallOrigin callOrigin;
-    private final UserType userType;
-    private final String reasonCode;
-    private final String comment;
+
+    protected final UUID userToken;
+    protected final String userName;
+    protected final CallOrigin callOrigin;
+    protected final UserType userType;
+    protected final String reasonCode;
+    protected final String comment;
 
     public CallContextBase(final String userName, final CallOrigin callOrigin, final UserType userType) {
         this(userName, callOrigin, userType, null);
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
index 081cd7e..e294d30 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
@@ -23,31 +23,102 @@ import org.joda.time.DateTime;
 import com.ning.billing.util.clock.Clock;
 
 public class DefaultCallContext extends CallContextBase {
-    private final Clock clock;
+
+    private final DateTime createdDate;
 
     public DefaultCallContext(final String userName, final CallOrigin callOrigin, final UserType userType, final UUID userToken, final Clock clock) {
         super(userName, callOrigin, userType, userToken);
-        this.clock = clock;
+        this.createdDate = clock.getUTCNow();
     }
 
     public DefaultCallContext(final String userName, final CallOrigin callOrigin, final UserType userType,
                               final String reasonCode, final String comment,
                               final UUID userToken, final Clock clock) {
         super(userName, callOrigin, userType, reasonCode, comment, userToken);
-        this.clock = clock;
+        this.createdDate = clock.getUTCNow();
     }
 
     public DefaultCallContext(final String userName, final CallOrigin callOrigin, final UserType userType, final Clock clock) {
         this(userName, callOrigin, userType, null, clock);
     }
 
+    public DefaultCallContext(final String userName, final DateTime createdDate, final String reasonCode,
+                              final String comment, final UUID userToken) {
+        super(userName, null, null, reasonCode, comment, userToken);
+        this.createdDate = createdDate;
+    }
+
     @Override
     public DateTime getCreatedDate() {
-        return clock.getUTCNow();
+        return createdDate;
     }
 
     @Override
     public DateTime getUpdatedDate() {
-        return clock.getUTCNow();
+        return createdDate;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("CallContextBase");
+        sb.append("{userToken=").append(userToken);
+        sb.append(", userName='").append(userName).append('\'');
+        sb.append(", callOrigin=").append(callOrigin);
+        sb.append(", userType=").append(userType);
+        sb.append(", reasonCode='").append(reasonCode).append('\'');
+        sb.append(", comment='").append(comment).append('\'');
+        sb.append(", createdDate='").append(createdDate).append('\'');
+        sb.append(", updatedDate='").append(createdDate).append('\'');
+        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 DefaultCallContext that = (DefaultCallContext) o;
+
+        if (callOrigin != that.callOrigin) {
+            return false;
+        }
+        if (comment != null ? !comment.equals(that.comment) : that.comment != null) {
+            return false;
+        }
+        if (reasonCode != null ? !reasonCode.equals(that.reasonCode) : that.reasonCode != null) {
+            return false;
+        }
+        if (userName != null ? !userName.equals(that.userName) : that.userName != null) {
+            return false;
+        }
+        if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
+            return false;
+        }
+        if (createdDate != null ? createdDate.compareTo(that.createdDate) != 0 : that.createdDate != null) {
+            return false;
+        }
+        if (userType != that.userType) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = userToken != null ? userToken.hashCode() : 0;
+        result = 31 * result + (userName != null ? userName.hashCode() : 0);
+        result = 31 * result + (callOrigin != null ? callOrigin.hashCode() : 0);
+        result = 31 * result + (userType != null ? userType.hashCode() : 0);
+        result = 31 * result + (reasonCode != null ? reasonCode.hashCode() : 0);
+        result = 31 * result + (comment != null ? comment.hashCode() : 0);
+        result = 31 * result + (createdDate != null ? createdDate.hashCode() : 0);
+        return result;
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditLogMapper.java b/util/src/main/java/com/ning/billing/util/dao/AuditLogMapper.java
new file mode 100644
index 0000000..89ca281
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditLogMapper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.dao;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.audit.DefaultAuditLog;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.DefaultCallContext;
+
+public class AuditLogMapper extends MapperBase implements ResultSetMapper<AuditLog> {
+
+    @Override
+    public AuditLog map(final int index, final ResultSet r, final StatementContext ctx) throws SQLException {
+        final String tableName = r.getString("table_name");
+        final long recordId = r.getLong("record_id");
+        final String changeType = r.getString("change_type");
+        final DateTime changeDate = getDateTime(r, "change_date");
+        final String changedBy = r.getString("changed_by");
+        final String reasonCode = r.getString("reason_code");
+        final String comments = r.getString("comments");
+        final String userToken = r.getString("user_token");
+
+        final EntityAudit entityAudit = new EntityAudit(TableName.valueOf(tableName), recordId, ChangeType.valueOf(changeType));
+        final CallContext callContext = new DefaultCallContext(changedBy, changeDate, reasonCode, comments, UUID.fromString(userToken));
+        return new DefaultAuditLog(entityAudit, callContext);
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java b/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
index 4f9c256..2e5d353 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
@@ -22,13 +22,18 @@ import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlBatch;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.customizers.Define;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 
+import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
 
 @ExternalizedSqlViaStringTemplate3
+@RegisterMapper(AuditLogMapper.class)
 public interface AuditSqlDao {
+
     @SqlUpdate
     public void insertAuditFromTransaction(@AuditBinder final EntityAudit audit,
                                            @CallContextBinder final CallContext context);
@@ -38,9 +43,17 @@ public interface AuditSqlDao {
                                            @CallContextBinder final CallContext context);
 
     @SqlQuery
+    public List<AuditLog> getAuditLogsForRecordId(@TableNameBinder final TableName tableName,
+                                                  @Bind("recordId") final long recordId);
+
+    @SqlQuery
     public Long getRecordId(@Bind("id") final String id);
 
     @SqlQuery
+    public Long getRecordIdForTable(@Define("tableName") final TableName tableName,
+                                    @Bind("id") final String id);
+
+    @SqlQuery
     public Long getHistoryRecordId(@Bind("recordId") final Long recordId);
 
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/TableName.java b/util/src/main/java/com/ning/billing/util/dao/TableName.java
index a5038d5..4dedcd0 100644
--- a/util/src/main/java/com/ning/billing/util/dao/TableName.java
+++ b/util/src/main/java/com/ning/billing/util/dao/TableName.java
@@ -16,31 +16,40 @@
 
 package com.ning.billing.util.dao;
 
+import javax.annotation.Nullable;
+
 public enum TableName {
-    ACCOUNT("accounts"),
-    ACCOUNT_HISTORY("account_history"),
-    ACCOUNT_EMAIL_HISTORY("account_email_history"),
-    BUNDLES("bundles"),
-    CUSTOM_FIELD_HISTORY("custom_field_history"),
-    INVOICE_ITEMS("invoice_items"),
-    INVOICE_PAYMENTS("invoice_payments"),
-    INVOICES("invoices"),
-    PAYMENT_ATTEMPTS("payment_attempts"),
-    PAYMENT_HISTORY("payment_history"),
-    PAYMENTS("payments"),
-    PAYMENT_METHODS("payment_methods"),
-    SUBSCRIPTIONS("subscriptions"),
-    SUBSCRIPTION_EVENTS("subscription_events"),
-    REFUNDS("refunds"),
-    TAG_HISTORY("tag_history");
+    ACCOUNT("accounts", ObjectType.ACCOUNT),
+    ACCOUNT_HISTORY("account_history", null),
+    ACCOUNT_EMAIL_HISTORY("account_email_history", ObjectType.ACCOUNT_EMAIL),
+    BUNDLES("bundles", ObjectType.BUNDLE),
+    CUSTOM_FIELD_HISTORY("custom_field_history", null),
+    INVOICE_ITEMS("invoice_items", ObjectType.INVOICE_ITEM),
+    INVOICE_PAYMENTS("invoice_payments", ObjectType.INVOICE_PAYMENT),
+    INVOICES("invoices", ObjectType.INVOICE),
+    PAYMENT_ATTEMPTS("payment_attempts", null),
+    PAYMENT_HISTORY("payment_history", null),
+    PAYMENTS("payments", ObjectType.PAYMENT),
+    PAYMENT_METHODS("payment_methods", ObjectType.PAYMENT_METHOD),
+    SUBSCRIPTIONS("subscriptions", ObjectType.SUBSCRIPTION),
+    SUBSCRIPTION_EVENTS("subscription_events", null),
+    REFUNDS("refunds", ObjectType.REFUND),
+    TAG_DEFINITIONS("tag_definitions", ObjectType.TAG_DEFINITION),
+    TAG_HISTORY("tag_history", null);
 
     private final String tableName;
+    private final ObjectType objectType;
 
-    TableName(final String tableName) {
+    TableName(final String tableName, @Nullable final ObjectType objectType) {
         this.tableName = tableName;
+        this.objectType = objectType;
     }
 
     public String getTableName() {
         return tableName;
     }
+
+    public ObjectType getObjectType() {
+        return objectType;
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/TableNameBinder.java b/util/src/main/java/com/ning/billing/util/dao/TableNameBinder.java
index 545186c..9cacf92 100644
--- a/util/src/main/java/com/ning/billing/util/dao/TableNameBinder.java
+++ b/util/src/main/java/com/ning/billing/util/dao/TableNameBinder.java
@@ -31,7 +31,9 @@ import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER})
 public @interface TableNameBinder {
+
     public static class TableNameBinderFactory implements BinderFactory {
+
         public Binder build(final Annotation annotation) {
             return new Binder<TableNameBinder, TableName>() {
                 public void bind(final SQLStatement q, final TableNameBinder bind, final TableName tableName) {
diff --git a/util/src/main/java/com/ning/billing/util/glue/AuditModule.java b/util/src/main/java/com/ning/billing/util/glue/AuditModule.java
new file mode 100644
index 0000000..0a1e8fb
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/glue/AuditModule.java
@@ -0,0 +1,34 @@
+/*
+ * 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.glue;
+
+import com.ning.billing.util.audit.dao.AuditDao;
+import com.ning.billing.util.audit.dao.DefaultAuditDao;
+
+import com.google.inject.AbstractModule;
+
+public class AuditModule extends AbstractModule {
+
+    protected void installDaos() {
+        bind(AuditDao.class).to(DefaultAuditDao.class).asEagerSingleton();
+    }
+
+    @Override
+    protected void configure() {
+        installDaos();
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
new file mode 100644
index 0000000..8ce34d0
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
@@ -0,0 +1,105 @@
+/*
+ * 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.audit.dao;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.bus.Bus;
+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.dao.TableName;
+import com.ning.billing.util.glue.AuditModule;
+import com.ning.billing.util.tag.MockTagStoreModuleSql;
+import com.ning.billing.util.tag.TagDefinition;
+import com.ning.billing.util.tag.dao.AuditedTagDao;
+import com.ning.billing.util.tag.dao.TagDefinitionDao;
+
+import com.google.inject.Inject;
+
+@Guice(modules = {MockTagStoreModuleSql.class, AuditModule.class})
+public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
+
+    @Inject
+    private TagDefinitionDao tagDefinitionDao;
+
+    @Inject
+    private AuditedTagDao tagDao;
+
+    @Inject
+    private AuditDao auditDao;
+
+    @Inject
+    private Clock clock;
+
+    @Inject
+    private Bus bus;
+
+    @Inject
+    private IDBI dbi;
+
+    private CallContext context;
+
+    @BeforeClass(groups = "slow")
+    public void setup() throws IOException {
+        context = new DefaultCallContextFactory(clock).createCallContext("Audit DAO test", CallOrigin.TEST, UserType.TEST, UUID.randomUUID());
+        bus.start();
+    }
+
+    @AfterClass(groups = "slow")
+    public void tearDown() {
+        bus.stop();
+    }
+
+    @Test(groups = "slow")
+    public void testRetrieveAudits() throws Exception {
+        final TagDefinition defYo = tagDefinitionDao.create("yo", "defintion yo", context);
+
+        // Create a tag
+        tagDao.insertTag(UUID.randomUUID(), ObjectType.ACCOUNT, defYo.getId(), context);
+
+        // Verify we get an audit entry for the tag_history table
+        final Handle handle = dbi.open();
+        final String tagHistoryString = (String) handle.select("select id from tag_history limit 1").get(0).get("id");
+        handle.close();
+
+        final List<AuditLog> auditLogs = auditDao.getAuditLogsForRecordId(TableName.TAG_HISTORY, UUID.fromString(tagHistoryString));
+        Assert.assertEquals(auditLogs.size(), 1);
+        Assert.assertEquals(auditLogs.get(0).getUserToken(), context.getUserToken().toString());
+        Assert.assertEquals(auditLogs.get(0).getChangeType(), ChangeType.INSERT);
+        Assert.assertNull(auditLogs.get(0).getComment());
+        Assert.assertNull(auditLogs.get(0).getReasonCode());
+        Assert.assertEquals(auditLogs.get(0).getUserName(), context.getUserName());
+        Assert.assertNotNull(auditLogs.get(0).getCreatedDate());
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/audit/TestDefaultAuditLog.java b/util/src/test/java/com/ning/billing/util/audit/TestDefaultAuditLog.java
new file mode 100644
index 0000000..709708f
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/audit/TestDefaultAuditLog.java
@@ -0,0 +1,84 @@
+/*
+ * 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.audit;
+
+import java.util.UUID;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.UtilTestSuite;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContext;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.EntityAudit;
+import com.ning.billing.util.dao.TableName;
+
+public class TestDefaultAuditLog extends UtilTestSuite {
+
+    @Test(groups = "fast")
+    public void testGetters() throws Exception {
+        final TableName tableName = TableName.ACCOUNT_EMAIL_HISTORY;
+        final long recordId = Long.MAX_VALUE;
+        final ChangeType changeType = ChangeType.DELETE;
+        final EntityAudit entityAudit = new EntityAudit(tableName, recordId, changeType);
+
+        final String userName = UUID.randomUUID().toString();
+        final CallOrigin callOrigin = CallOrigin.EXTERNAL;
+        final UserType userType = UserType.CUSTOMER;
+        final UUID userToken = UUID.randomUUID();
+        final ClockMock clock = new ClockMock();
+        final CallContext callContext = new DefaultCallContext(userName, callOrigin, userType, userToken, clock);
+
+        final AuditLog auditLog = new DefaultAuditLog(entityAudit, callContext);
+        Assert.assertEquals(auditLog.getChangeType(), changeType);
+        Assert.assertNull(auditLog.getComment());
+        Assert.assertNotNull(auditLog.getCreatedDate());
+        Assert.assertNull(auditLog.getReasonCode());
+        Assert.assertEquals(auditLog.getUserName(), userName);
+        Assert.assertEquals(auditLog.getUserToken(), userToken.toString());
+    }
+
+    @Test(groups = "fast")
+    public void testEquals() throws Exception {
+        final TableName tableName = TableName.ACCOUNT_EMAIL_HISTORY;
+        final long recordId = Long.MAX_VALUE;
+        final ChangeType changeType = ChangeType.DELETE;
+        final EntityAudit entityAudit = new EntityAudit(tableName, recordId, changeType);
+
+        final String userName = UUID.randomUUID().toString();
+        final CallOrigin callOrigin = CallOrigin.EXTERNAL;
+        final UserType userType = UserType.CUSTOMER;
+        final UUID userToken = UUID.randomUUID();
+        final ClockMock clock = new ClockMock();
+        final CallContext callContext = new DefaultCallContext(userName, callOrigin, userType, userToken, clock);
+
+        final AuditLog auditLog = new DefaultAuditLog(entityAudit, callContext);
+        Assert.assertEquals(auditLog, auditLog);
+
+        final AuditLog sameAuditLog = new DefaultAuditLog(entityAudit, callContext);
+        Assert.assertEquals(sameAuditLog, auditLog);
+
+        clock.addMonths(1);
+        final CallContext otherCallContext = new DefaultCallContext(userName, callOrigin, userType, userToken, clock);
+        final AuditLog otherAuditLog = new DefaultAuditLog(entityAudit, otherCallContext);
+        Assert.assertNotEquals(otherAuditLog, auditLog);
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/callcontext/TestDefaultCallContext.java b/util/src/test/java/com/ning/billing/util/callcontext/TestDefaultCallContext.java
new file mode 100644
index 0000000..c56b5f3
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/callcontext/TestDefaultCallContext.java
@@ -0,0 +1,69 @@
+/*
+ * 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.callcontext;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.util.UtilTestSuite;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+
+public class TestDefaultCallContext extends UtilTestSuite {
+
+    private final Clock clock = new ClockMock();
+
+    @Test(groups = "fast")
+    public void testGetters() throws Exception {
+        final String userName = UUID.randomUUID().toString();
+        final DateTime createdDate = clock.getUTCNow();
+        final String reasonCode = UUID.randomUUID().toString();
+        final String comment = UUID.randomUUID().toString();
+        final UUID userToken = UUID.randomUUID();
+        final DefaultCallContext callContext = new DefaultCallContext(userName, createdDate, reasonCode, comment, userToken);
+
+        Assert.assertEquals(callContext.getCreatedDate(), createdDate);
+        Assert.assertNull(callContext.getCallOrigin());
+        Assert.assertEquals(callContext.getComment(), comment);
+        Assert.assertEquals(callContext.getReasonCode(), reasonCode);
+        Assert.assertEquals(callContext.getUserName(), userName);
+        Assert.assertEquals(callContext.getUpdatedDate(), createdDate);
+        Assert.assertEquals(callContext.getUserToken(), userToken);
+        Assert.assertNull(callContext.getUserType());
+    }
+
+    @Test(groups = "fast")
+    public void testEquals() throws Exception {
+        final String userName = UUID.randomUUID().toString();
+        final DateTime createdDate = clock.getUTCNow();
+        final String reasonCode = UUID.randomUUID().toString();
+        final String comment = UUID.randomUUID().toString();
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultCallContext callContext = new DefaultCallContext(userName, createdDate, reasonCode, comment, userToken);
+        Assert.assertEquals(callContext, callContext);
+
+        final DefaultCallContext sameCallContext = new DefaultCallContext(userName, createdDate, reasonCode, comment, userToken);
+        Assert.assertEquals(sameCallContext, callContext);
+
+        final DefaultCallContext otherCallContext = new DefaultCallContext(UUID.randomUUID().toString(), createdDate, reasonCode, comment, userToken);
+        Assert.assertNotEquals(otherCallContext, callContext);
+    }
+}