killbill-memoizeit

updates to remove save/load from entities; transaction support

12/2/2011 3:25:52 PM

Changes

Details

diff --git a/account/src/main/java/com/ning/billing/account/api/Account.java b/account/src/main/java/com/ning/billing/account/api/Account.java
index f3fbfeb..435e344 100644
--- a/account/src/main/java/com/ning/billing/account/api/Account.java
+++ b/account/src/main/java/com/ning/billing/account/api/Account.java
@@ -16,15 +16,12 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.account.dao.IAccountDao;
-import com.ning.billing.account.glue.InjectorMagic;
 import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.util.eventbus.IEventBusType;
 
 import java.util.UUID;
 
 public class Account extends CustomizableEntityBase implements IAccount {
-    private static IAccountDao dao;
+    public final static String OBJECT_TYPE = "Account";
 
     private String externalKey;
     private String email;
@@ -34,31 +31,26 @@ public class Account extends CustomizableEntityBase implements IAccount {
     private Currency currency;
     private int billCycleDay;
 
-    private IAccount originalData;
-
-    public Account() {
-        this(UUID.randomUUID());
+    public Account(IAccountData data) {
+        this(UUID.randomUUID(), data.getExternalKey(), data.getEmail(), data.getFirstName(), data.getLastName(),
+                data.getPhone(), data.getCurrency(), data.getBillCycleDay());
     }
 
-    public Account(UUID id) {
+    public Account(UUID id, String externalKey, String email, String firstName, String lastName,
+                   String phone, Currency currency, int billCycleDay) {
         super(id);
-        dao = InjectorMagic.getAccountDao();
-    }
-
-    public Account(IAccountData data) {
-        this();
-        this.externalKey = data.getExternalKey();
-        this.email = data.getEmail();
-        this.firstName = data.getFirstName();
-        this.lastName = data.getLastName();
-        this.phone = data.getPhone();
-        this.currency = data.getCurrency();
-        this.billCycleDay = data.getBillCycleDay();
+        this.externalKey = externalKey;
+        this.email = email;
+        this.firstName = firstName;
+        this.lastName = lastName;
+        this.phone = phone;
+        this.currency = currency;
+        this.billCycleDay = billCycleDay;
     }
 
     @Override
     public String getObjectName() {
-        return "Account";
+        return OBJECT_TYPE;
     }
 
     @Override
@@ -66,9 +58,17 @@ public class Account extends CustomizableEntityBase implements IAccount {
         return externalKey;
     }
 
-    public Account externalKey(String externalKey) {
+    public void setExternalKey(String externalKey) {
         this.externalKey = externalKey;
-        return this;
+    }
+
+    @Override
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
     }
 
     @Override
@@ -76,9 +76,8 @@ public class Account extends CustomizableEntityBase implements IAccount {
         return firstName;
     }
 
-    public Account firstName(String firstName) {
+    public void setFirstName(String firstName) {
         this.firstName = firstName;
-        return this;
     }
 
     @Override
@@ -86,19 +85,8 @@ public class Account extends CustomizableEntityBase implements IAccount {
         return lastName;
     }
 
-    public Account lastName(String lastName) {
+    public void setLastName(String lastName) {
         this.lastName = lastName;
-        return this;
-    }
-
-    @Override
-    public String getEmail() {
-        return email;
-    }
-
-    public Account email(String email) {
-        this.email = email;
-        return this;
     }
 
     @Override
@@ -106,19 +94,8 @@ public class Account extends CustomizableEntityBase implements IAccount {
         return phone;
     }
 
-    public Account phone(String phone) {
+    public void setPhone(String phone) {
         this.phone = phone;
-        return this;
-    }
-
-    @Override
-    public int getBillCycleDay() {
-        return billCycleDay;
-    }
-
-    public Account billCycleDay(int billCycleDay) {
-        this.billCycleDay = billCycleDay;
-        return this;
     }
 
     @Override
@@ -126,64 +103,16 @@ public class Account extends CustomizableEntityBase implements IAccount {
         return currency;
     }
 
-    public Account currency(Currency currency) {
+    public void setCurrency(Currency currency) {
         this.currency = currency;
-        return this;
-    }
-
-    public static Account create() {
-        return new Account();
-    }
-
-    public static Account create(UUID id) {
-        return new Account(id);
-    }
-
-    public static Account loadAccount(UUID id) {
-        Account account = (Account) dao.getAccountById(id);
-        if (account != null) {
-            account.loadCustomFields();
-        }
-        return account;
-    }
-
-    public static Account loadAccount(String key) {
-        Account account = (Account) dao.getAccountByKey(key);
-        if (account != null) {
-            account.loadCustomFields();
-        }
-        return account;
-    }
-
-    @Override
-    protected void saveObject() {
-        dao.saveAccount(this);
-    }
-
-    @Override
-    protected void updateObject() {
-        dao.updateAccount(this);
     }
 
     @Override
-    protected IEventBusType getCreateEvent() {
-        return new AccountCreation(id, this);
-    }
-
-    @Override
-    protected IEventBusType getUpdateEvent() {
-        return new AccountChange(id, originalData, this);
+    public int getBillCycleDay() {
+        return billCycleDay;
     }
 
-    @Override
-    protected void loadObject() {
-        this.originalData = dao.getAccountById(id);
-        this.externalKey = originalData.getExternalKey();
-        this.email = originalData.getEmail();
-        this.firstName = originalData.getFirstName();
-        this.lastName = originalData.getLastName();
-        this.phone = originalData.getPhone();
-        this.currency = originalData.getCurrency();
-        this.billCycleDay = originalData.getBillCycleDay();
+    public void setBillCycleDay(int billCycleDay) {
+        this.billCycleDay = billCycleDay;
     }
 }
diff --git a/account/src/main/java/com/ning/billing/account/api/CustomField.java b/account/src/main/java/com/ning/billing/account/api/CustomField.java
index bae8d86..134ec83 100644
--- a/account/src/main/java/com/ning/billing/account/api/CustomField.java
+++ b/account/src/main/java/com/ning/billing/account/api/CustomField.java
@@ -18,31 +18,18 @@ package com.ning.billing.account.api;
 
 import java.util.UUID;
 
-public class CustomField implements ICustomField {
-    private UUID id;
+public class CustomField extends EntityBase<ICustomField> implements ICustomField {
     private String name;
     private String value;
-    private boolean isNew;
 
     public CustomField(String name, String value) {
         this(UUID.randomUUID(), name, value);
-        this.isNew = true;
     }
 
     public CustomField(UUID id, String name, String value) {
-        this.id = id;
+        super(id);
         this.name = name;
         this.value = value;
-        this.isNew = false;
-    }
-
-    @Override
-    public UUID getId() {
-        return id;
-    }
-
-    public String getIdAsString() {
-        return id.toString();
     }
 
     @Override
@@ -56,16 +43,6 @@ public class CustomField implements ICustomField {
     }
 
     @Override
-    public boolean isNew() {
-        return this.isNew;
-    }
-
-    @Override
-    public void setAsSaved() {
-        this.isNew = false;
-    }
-
-    @Override
     public void setValue(String value) {
         this.value = value;
     }
diff --git a/account/src/main/java/com/ning/billing/account/api/CustomizableEntityBase.java b/account/src/main/java/com/ning/billing/account/api/CustomizableEntityBase.java
index e266428..40a78eb 100644
--- a/account/src/main/java/com/ning/billing/account/api/CustomizableEntityBase.java
+++ b/account/src/main/java/com/ning/billing/account/api/CustomizableEntityBase.java
@@ -19,7 +19,7 @@ package com.ning.billing.account.api;
 import java.util.UUID;
 
 public abstract class CustomizableEntityBase extends EntityBase implements ICustomizableEntity {
-    protected final FieldStore fields;
+    protected final IFieldStore fields;
 
     public CustomizableEntityBase(UUID id) {
         super(id);
@@ -37,24 +37,9 @@ public abstract class CustomizableEntityBase extends EntityBase implements ICust
     }
 
     @Override
-    public void save() {
-        super.save();
-        fields.save();
-    }
-
-    @Override
-    public void load() {
-        loadObject();
-        loadCustomFields();
-    }
-
-    protected void loadCustomFields() {
-        fields.load();
+    public IFieldStore getFields() {
+        return fields;
     }
 
     public abstract String getObjectName();
-
-    protected abstract void saveObject();
-
-    protected abstract void loadObject();
 }
diff --git a/account/src/main/java/com/ning/billing/account/api/EntityBase.java b/account/src/main/java/com/ning/billing/account/api/EntityBase.java
index f4283d5..4fe8da2 100644
--- a/account/src/main/java/com/ning/billing/account/api/EntityBase.java
+++ b/account/src/main/java/com/ning/billing/account/api/EntityBase.java
@@ -16,30 +16,17 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.account.glue.InjectorMagic;
-import com.ning.billing.util.eventbus.IEventBus;
-import com.ning.billing.util.eventbus.IEventBusType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.util.UUID;
 
-public abstract class EntityBase implements IEntity, IPersistable {
-    protected final Logger log = LoggerFactory.getLogger(this.getClass());
-    private static IEventBus eventBus;
-
+public abstract class EntityBase<T> implements IEntity {
     protected final UUID id;
-    protected boolean isNew;
 
     public EntityBase(UUID id) {
-        eventBus = InjectorMagic.getEventBus();
         this.id = id;
-        this.isNew = false;
     }
 
     public EntityBase() {
         this(UUID.randomUUID());
-        this.isNew = true;
     }
 
     @Override
@@ -48,47 +35,7 @@ public abstract class EntityBase implements IEntity, IPersistable {
     }
 
     @Override
-    public boolean isNew() {
-        return this.isNew;
-    }
-
-    @Override
-    public void setAsSaved() {
-        this.isNew = false;
+    public String getIdAsString() {
+        return id.toString();
     }
-
-    @Override
-    public void save() {
-        IEventBusType event;
-
-        if (isNew) {
-            event = getCreateEvent();
-            saveObject();
-        } else {
-            event = getUpdateEvent();
-            updateObject();
-        }
-
-        if (event != null) {
-            try {
-                eventBus.post(event);
-            } catch (IEventBus.EventBusException evbe) {
-                log.error("Failed to post account change to event bus during save.", evbe);
-            }
-        }
-    }
-
-    protected abstract void saveObject();
-    protected abstract void updateObject();
-
-    protected IEventBusType getCreateEvent() {
-        return null;
-    }
-
-    protected IEventBusType getUpdateEvent() {
-        return null;
-    }
-
-    @Override
-    public abstract void load();
-}
+}
\ No newline at end of file
diff --git a/account/src/main/java/com/ning/billing/account/api/EntityCollectionBase.java b/account/src/main/java/com/ning/billing/account/api/EntityCollectionBase.java
index 61d7bd1..2ed4f86 100644
--- a/account/src/main/java/com/ning/billing/account/api/EntityCollectionBase.java
+++ b/account/src/main/java/com/ning/billing/account/api/EntityCollectionBase.java
@@ -16,11 +16,11 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.account.dao.IEntityCollectionDao;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
 
-import java.util.*;
-
-public abstract class EntityCollectionBase<T extends IEntity> {
+public abstract class EntityCollectionBase<T extends IEntity> implements IEntityCollection<T> {
     protected Map<String, T> entities = new HashMap<String, T>();
     protected final UUID objectId;
     protected final String objectType;
@@ -30,54 +30,29 @@ public abstract class EntityCollectionBase<T extends IEntity> {
         this.objectType = objectType;
     }
 
-    public List<T> getNewEntities() {
-        List<T> newEntities = new ArrayList<T>();
-        for (T entity : entities.values()) {
-            if (entity.isNew()) {
-                newEntities.add(entity);
-            }
-        }
-
-        return newEntities;
-    }
-
-    public List<T> getUpdatedEntities() {
-        List<T> updatedEntities = new ArrayList<T>();
-        for (T entity : entities.values()) {
-            if (!entity.isNew()) {
-                updatedEntities.add(entity);
-            }
-        }
-
-        return updatedEntities;
-    }
-
-    public void save() {
-        IEntityCollectionDao<T> dao = getCollectionDao();
-
-        dao.create(objectId.toString(), objectType, getNewEntities());
-        dao.update(objectId.toString(), objectType, getUpdatedEntities());
-        setEntitiesAsSaved();
-    }
-
-    private void setEntitiesAsSaved() {
-        for (T entity : entities.values()) {
-            entity.setAsSaved();
-        }
-    }
-
-    public void load() {
-        IEntityCollectionDao<T> dao = getCollectionDao();
-
-        List<T> entities = dao.load(objectId.toString(), objectType);
-        this.entities.clear();
-        if (entities != null) {
-            for (T entity : entities) {
-                this.entities.put(getEntityKey(entity), entity);
-            }
-        }
+    @Override
+    public void clear() {
+        entities.clear();
     }
 
-    protected abstract String getEntityKey(T entity);
-    protected abstract IEntityCollectionDao<T> getCollectionDao();
+    @Override
+    public abstract String getEntityKey(T entity);
+
+//    public void save() {
+//        IEntityCollectionDao<T> dao = getCollectionDao();
+//
+//        dao.save(objectId.toString(), objectType, new ArrayList(entities.values()));
+//    }
+//
+//    public void load() {
+//        IEntityCollectionDao<T> dao = getCollectionDao();
+//
+//        List<T> entities = dao.load(objectId.toString(), objectType);
+//        this.entities.clear();
+//        if (entities != null) {
+//            for (T entity : entities) {
+//                this.entities.put(getEntityKey(entity), entity);
+//            }
+//        }
+//    }
 }
diff --git a/account/src/main/java/com/ning/billing/account/api/FieldStore.java b/account/src/main/java/com/ning/billing/account/api/FieldStore.java
index 0a58da4..61214c8 100644
--- a/account/src/main/java/com/ning/billing/account/api/FieldStore.java
+++ b/account/src/main/java/com/ning/billing/account/api/FieldStore.java
@@ -16,12 +16,11 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.account.dao.IEntityCollectionDao;
-import com.ning.billing.account.glue.InjectorMagic;
-
+import java.util.ArrayList;
+import java.util.List;
 import java.util.UUID;
 
-public class FieldStore extends EntityCollectionBase<ICustomField> {
+public class FieldStore extends EntityCollectionBase<ICustomField> implements IFieldStore {
     public FieldStore(UUID objectId, String objectType) {
         super(objectId, objectType);
     }
@@ -31,15 +30,10 @@ public class FieldStore extends EntityCollectionBase<ICustomField> {
     }
 
     @Override
-    protected String getEntityKey(ICustomField entity) {
+    public String getEntityKey(ICustomField entity) {
         return entity.getName();
     }
 
-    @Override
-    protected IEntityCollectionDao<ICustomField> getCollectionDao() {
-        return InjectorMagic.getFieldStoreDao();
-    }
-
     public void setValue(String fieldName, String fieldValue) {
         if (entities.containsKey(fieldName)) {
             entities.get(fieldName).setValue(fieldValue);
@@ -55,91 +49,21 @@ public class FieldStore extends EntityCollectionBase<ICustomField> {
             return null;
         }
     }
-}
-//import com.ning.billing.account.dao.IFieldStoreDao;
-//import com.ning.billing.account.glue.InjectorMagic;
-//
-//import java.util.*;
-//
-//public class FieldStore implements IFieldStore {
-//    private Map<String, ICustomField> fields = new HashMap<String, ICustomField>();
-//    private final UUID objectId;
-//    private final String objectType;
-//
-//    public FieldStore(UUID objectId, String objectType) {
-//        this.objectId = objectId;
-//        this.objectType = objectType;
-//    }
-//
-//    public static FieldStore create(UUID objectId, String objectType) {
-//        return new FieldStore(objectId, objectType);
-//    }
-//
-//    public void setValue(String fieldName, String fieldValue) {
-//        if (fields.containsKey(fieldName)) {
-//            fields.get(fieldName).setValue(fieldValue);
-//        } else {
-//            fields.put(fieldName, new CustomField(fieldName, fieldValue));
-//        }
-//    }
-//
-//    public String getValue(String fieldName) {
-//        if (fields.containsKey(fieldName)) {
-//            return fields.get(fieldName).getValue();
-//        } else {
-//            return null;
-//        }
-//    }
-//
-//    @Override
-//    public List<ICustomField> getNewFields() {
-//        List<ICustomField> newFields = new ArrayList<ICustomField>();
-//        for (ICustomField field : fields.values()) {
-//            if (field.isNew()) {
-//                newFields.add(field);
-//            }
-//        }
-//
-//        return newFields;
-//    }
-//
-//    @Override
-//    public List<ICustomField> getUpdatedFields() {
-//        List<ICustomField> updatedFields = new ArrayList<ICustomField>();
-//        for (ICustomField field : fields.values()) {
-//            if (!field.isNew()) {
-//                updatedFields.add(field);
-//            }
-//        }
-//
-//        return updatedFields;
-//    }
-//
-//    public void save() {
-//        IFieldStoreDao dao = InjectorMagic.getFieldStoreDao();
-//
-//        List<ICustomField> newFields = getNewFields();
-//        dao.createFields(objectId.toString(), objectType, newFields);
-//        setEntitiesAsSaved();
-//
-//        dao.saveFields(objectId.toString(), objectType, getUpdatedFields());
-//    }
-//
-//    private void setEntitiesAsSaved() {
-//        for (ICustomField field : fields.values()) {
-//            field.setAsSaved();
-//        }
-//    }
-//
-//    public void load() {
-//        IFieldStoreDao dao = InjectorMagic.getFieldStoreDao();
-//
-//        List<ICustomField> fields = dao.getFields(objectId.toString(), objectType);
-//        this.fields.clear();
-//        if (fields != null) {
-//            for (ICustomField field : fields) {
-//                this.fields.put(field.getName(), field);
-//            }
-//        }
-//    }
-//}
\ No newline at end of file
+
+    @Override
+    public List<ICustomField> getFieldList() {
+        return new ArrayList<ICustomField>(entities.values());
+    }
+
+    @Override
+    public void add(ICustomField field) {
+        entities.put(field.getName(), field);
+    }
+
+    @Override
+    public void add(List<ICustomField> fields) {
+        for (ICustomField field : fields) {
+            add(field);
+        }
+    }
+}
\ No newline at end of file
diff --git a/account/src/main/java/com/ning/billing/account/api/Tag.java b/account/src/main/java/com/ning/billing/account/api/Tag.java
index edac97f..9df2313 100644
--- a/account/src/main/java/com/ning/billing/account/api/Tag.java
+++ b/account/src/main/java/com/ning/billing/account/api/Tag.java
@@ -16,14 +16,11 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.account.dao.ITagDao;
 import org.joda.time.DateTime;
 
 import java.util.UUID;
 
 public class Tag extends EntityBase {
-    private ITagDao dao;
-
     private UUID tagDescriptionId;
     private String description;
     private UUID objectId;
@@ -31,16 +28,9 @@ public class Tag extends EntityBase {
     private String addedBy;
     private DateTime dateAdded;
 
-    public Tag() {
-        super();
-    }
-
-    public Tag(UUID id) {
-        super(id);
-    }
-
-    public Tag(UUID id, String description, UUID objectId, String objectType, String addedBy, DateTime dateAdded) {
+    public Tag(UUID id, UUID tagDescriptionId, String description, UUID objectId, String objectType, String addedBy, DateTime dateAdded) {
         super(id);
+        this.tagDescriptionId = tagDescriptionId;
         this.description = description;
         this.objectId = objectId;
         this.objectType = objectType;
@@ -64,24 +54,11 @@ public class Tag extends EntityBase {
         return objectType;
     }
 
-    @Override
-    protected void saveObject() {
-        dao.create(this);
-    }
-
-    @Override
-    protected void updateObject() {
-        dao.update(this);
+    public String getAddedBy() {
+        return addedBy;
     }
 
-    @Override
-    public void load() {
-        Tag that = dao.load(id);
-        if (that != null) {
-            this.tagDescriptionId = that.tagDescriptionId;
-            this.description = that.description;
-            this.objectId = that.objectId;
-            this.objectType = that.objectType;
-        }
+    public DateTime getDateAdded() {
+        return dateAdded;
     }
 }
diff --git a/account/src/main/java/com/ning/billing/account/api/TagBuilder.java b/account/src/main/java/com/ning/billing/account/api/TagBuilder.java
new file mode 100644
index 0000000..1562c3c
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/api/TagBuilder.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010-2011 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.account.api;
+
+import org.joda.time.DateTime;
+
+import java.util.UUID;
+
+public class TagBuilder {
+    private UUID id = UUID.randomUUID();
+    private UUID tagDescriptionId;
+    private String description;
+    private UUID objectId;
+    private String objectType;
+    private String addedBy;
+    private DateTime dateAdded;
+
+    public TagBuilder id(UUID id) {
+        this.id = id;
+        return this;
+    }
+
+    public TagBuilder tagDescriptionId(UUID tagDescriptionId) {
+        this.tagDescriptionId = tagDescriptionId;
+        return this;
+    }
+
+    public TagBuilder description(String description) {
+        this.description = description;
+        return this;
+    }
+
+    public TagBuilder objectId(UUID objectId) {
+        this.objectId = objectId;
+        return this;
+    }
+
+    public TagBuilder objectType(String objectType) {
+        this.objectType = objectType;
+        return this;
+    }
+
+    public TagBuilder addedBy(String addedBy) {
+        this.addedBy = addedBy;
+        return this;
+    }
+
+    public TagBuilder dateAdded(DateTime dateAdded) {
+        this.dateAdded = dateAdded;
+        return this;
+    }
+
+    public Tag build() {
+        return new Tag(id, tagDescriptionId, description, objectId, objectType, addedBy, dateAdded);
+    }
+}
diff --git a/account/src/main/java/com/ning/billing/account/api/TagDescription.java b/account/src/main/java/com/ning/billing/account/api/TagDescription.java
index 5618ca8..3da6fe0 100644
--- a/account/src/main/java/com/ning/billing/account/api/TagDescription.java
+++ b/account/src/main/java/com/ning/billing/account/api/TagDescription.java
@@ -16,14 +16,11 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.account.dao.ITagDescriptionDao;
 import org.joda.time.DateTime;
 
 import java.util.UUID;
 
 public class TagDescription extends EntityBase {
-    private ITagDescriptionDao dao;
-
     private String name;
     private String addedBy;
     private DateTime created;
@@ -43,74 +40,23 @@ public class TagDescription extends EntityBase {
         return name;
     }
 
-    public TagDescription withName(String name) {
-        this.name = name;
-        return this;
-    }
-
     public String getAddedBy() {
         return addedBy;
     }
 
-    public TagDescription withAddedBy(String addedBy) {
-        this.addedBy = addedBy;
-        return this;
-    }
-
     public DateTime getCreated() {
         return created;
     }
 
-    public TagDescription withCreated(DateTime created) {
-        this.created = created;
-        return this;
-    }
-
     public String getDescription() {
         return description;
     }
 
-    public TagDescription withDescription(String description) {
-        this.description = description;
-        return this;
-    }
-
     public boolean getGenerateInvoice() {
         return generateInvoice;
     }
 
-    public TagDescription withGenerateInvoice(boolean generateInvoice) {
-        this.generateInvoice = generateInvoice;
-        return this;
-    }
-
     public boolean getProcessPayment() {
         return processPayment;
     }
-
-    public TagDescription withProcessPayment(boolean processPayment) {
-        this.processPayment = processPayment;
-        return this;
-    }
-
-    @Override
-    protected void saveObject() {
-        dao.create(this);
-    }
-
-    @Override
-    protected void updateObject() {
-        dao.update(this);
-    }
-
-    @Override
-    public void load() {
-        TagDescription that = dao.load(id.toString());
-        this.name = that.name;
-        this.addedBy = that.addedBy;
-        this.created = that.created;
-        this.description = that.description;
-        this.generateInvoice = that.generateInvoice;
-        this.processPayment = that.processPayment;
-    }
 }
diff --git a/account/src/main/java/com/ning/billing/account/api/TagStore.java b/account/src/main/java/com/ning/billing/account/api/TagStore.java
index dda8884..b847e11 100644
--- a/account/src/main/java/com/ning/billing/account/api/TagStore.java
+++ b/account/src/main/java/com/ning/billing/account/api/TagStore.java
@@ -16,9 +16,6 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.account.dao.IEntityCollectionDao;
-import com.ning.billing.account.glue.InjectorMagic;
-
 import java.util.UUID;
 
 public class TagStore extends EntityCollectionBase<Tag> {
@@ -27,14 +24,12 @@ public class TagStore extends EntityCollectionBase<Tag> {
     }
 
     @Override
-    protected String getEntityKey(Tag entity) {
+    public String getEntityKey(Tag entity) {
         return entity.getDescription();
     }
 
-    @Override
-    protected IEntityCollectionDao<Tag> getCollectionDao() {
-        return InjectorMagic.getTagStoreDao();
-    }
-
-
+//    @Override
+//    protected IEntityCollectionDao<Tag> getCollectionDao() {
+//        return InjectorMagic.getTagStoreDao();
+//    }
 }
\ No newline at end of file
diff --git a/account/src/main/java/com/ning/billing/account/api/user/AccountBuilder.java b/account/src/main/java/com/ning/billing/account/api/user/AccountBuilder.java
new file mode 100644
index 0000000..75dea6d
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/api/user/AccountBuilder.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010-2011 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.account.api.user;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.catalog.api.Currency;
+
+import java.util.UUID;
+
+public class AccountBuilder {
+    private UUID id;
+    private String externalKey;
+    private String email;
+    private String firstName;
+    private String lastName;
+    private String phone;
+    private Currency currency;
+    private int billCycleDay;
+
+    public AccountBuilder() {
+        this(UUID.randomUUID());
+    }
+
+    public AccountBuilder(UUID id) {
+        this.id = id;
+    }
+
+    public AccountBuilder externalKey(String externalKey) {
+        this.externalKey = externalKey;
+        return this;
+    }
+
+    public AccountBuilder email(String email) {
+        this.email = email;
+        return this;
+    }
+
+    public AccountBuilder firstName(String firstName) {
+        this.firstName = firstName;
+        return this;
+    }
+
+    public AccountBuilder lastName(String lastName) {
+        this.lastName = lastName;
+        return this;
+    }
+
+    public AccountBuilder phone(String phone) {
+        this.phone = phone;
+        return this;
+    }
+
+    public AccountBuilder billCycleDay(int billCycleDay) {
+        this.billCycleDay = billCycleDay;
+        return this;
+    }
+
+    public AccountBuilder currency(Currency currency) {
+        this.currency = currency;
+        return this;
+    }
+
+    public Account build() {
+        return new Account(id, externalKey, email, firstName, lastName, phone, currency, billCycleDay);
+    }
+}
diff --git a/account/src/main/java/com/ning/billing/account/core/Engine.java b/account/src/main/java/com/ning/billing/account/core/Engine.java
index 82fcf29..6497353 100644
--- a/account/src/main/java/com/ning/billing/account/core/Engine.java
+++ b/account/src/main/java/com/ning/billing/account/core/Engine.java
@@ -16,7 +16,7 @@
 
 package com.ning.billing.account.core;
 
-import com.ning.billing.account.api.IAccountChange;
+import com.ning.billing.account.api.IAccountChangeEvent;
 import com.ning.billing.account.api.IAccountService;
 import com.ning.billing.account.api.IAccountUserApi;
 import com.ning.billing.lifecycle.LyfecycleHandlerType;
@@ -62,11 +62,11 @@ public class Engine implements IAccountService, IAccountChangeListener {
     }
 
     @Override
-    public void processAccountChange(IAccountChange change) {
+    public void processAccountChange(IAccountChangeEvent changeEvent) {
         try {
-            eventBus.post(change);
+            eventBus.post(changeEvent);
         } catch (IEventBus.EventBusException e) {
-            log.warn("Failed to post account change event.");
+            log.warn("Failed to post account changeEvent event.");
         }
     }
 }
diff --git a/account/src/main/java/com/ning/billing/account/core/IAccountChangeListener.java b/account/src/main/java/com/ning/billing/account/core/IAccountChangeListener.java
index 6abd970..0964df9 100644
--- a/account/src/main/java/com/ning/billing/account/core/IAccountChangeListener.java
+++ b/account/src/main/java/com/ning/billing/account/core/IAccountChangeListener.java
@@ -16,8 +16,8 @@
 
 package com.ning.billing.account.core;
 
-import com.ning.billing.account.api.IAccountChange;
+import com.ning.billing.account.api.IAccountChangeEvent;
 
 public interface IAccountChangeListener {
-    public void processAccountChange(IAccountChange change);
+    public void processAccountChange(IAccountChangeEvent changeEvent);
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
index 6f5c5fb..b4d8dc3 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
@@ -17,56 +17,123 @@
 package com.ning.billing.account.dao;
 
 import com.google.inject.Inject;
-import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.IAccount;
-import com.ning.billing.account.api.IAccountData;
+import com.ning.billing.account.api.*;
+import com.ning.billing.account.api.user.AccountChangeEvent;
+import com.ning.billing.account.api.user.AccountCreationEvent;
+import com.ning.billing.util.eventbus.IEventBus;
+import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
 
 import java.util.List;
-import java.util.UUID;
 
 public class AccountDao implements IAccountDao {
-    private final IAccountDaoSql dao;
+    private final IAccountDao accountDao;
+    private final IFieldStoreDao fieldStoreDao;
+    private final IDBI dbi; // needed for transaction support
+    private final IEventBus eventBus;
 
     @Inject
-    public AccountDao(IDBI dbi) {
-        this.dao = dbi.onDemand(IAccountDaoSql.class);
+    public AccountDao(IDBI dbi, IEventBus eventBus) {
+        this.dbi = dbi;
+        this.eventBus = eventBus;
+        this.accountDao = dbi.onDemand(IAccountDao.class);
+        this.fieldStoreDao = dbi.onDemand(IFieldStoreDao.class);
     }
 
     @Override
-    public IAccount createAccount(IAccountData input) {
-        IAccount result = new Account(input);
-        dao.insertAccount(result);
-        return result;
+    public IAccount getAccountByKey(String key) {
+        IAccount account = accountDao.getAccountByKey(key);
+        if (account != null) {
+            loadFields(account);
+        }
+        return account;
     }
 
     @Override
-    public IAccount getAccountByKey(String key) {
-        return dao.getAccountByKey(key);
+    public IAccount getById(String id) {
+        IAccount account = accountDao.getById(id);
+        if (account != null) {
+            loadFields(account);
+        }
+        return account;
     }
 
-    @Override
-    public IAccount getAccountById(UUID uid) {
-        return dao.getAccountById(uid.toString());
+    private void loadFields(IAccount account) {
+        List<ICustomField> fields = fieldStoreDao.load(account.getId().toString(), Account.OBJECT_TYPE);
+        account.getFields().clear();
+        if (fields != null) {
+            for (ICustomField field : fields) {
+                account.getFields().setValue(field.getName(), field.getValue());
+            }
+        }
     }
 
     @Override
-    public List<IAccount> getAccounts() {
-        return dao.getAccounts();
+    public List<IAccount> get() {
+        return accountDao.get();
     }
 
     @Override
     public void test() {
-        dao.test();
+        accountDao.test();
     }
 
     @Override
-    public void saveAccount(IAccount account) {
-        dao.insertAccount(account);
-    }
+    public void save(final IAccount account) {
+        final String accountId = account.getId().toString();
+        final String objectType = Account.OBJECT_TYPE;
 
-    @Override
-    public void updateAccount(IAccount account) {
-        dao.updateAccount(account);
+        dbi.inTransaction(new TransactionCallback<Void>() {
+            @Override
+            public Void inTransaction(Handle conn, TransactionStatus status) throws Exception {
+                try {
+                    conn.begin();
+
+                    IAccountDao accountDao = conn.attach(IAccountDao.class);
+                    IAccount currentAccount = accountDao.getById(accountId);
+                    accountDao.save(account);
+
+                    IFieldStore fieldStore = account.getFields();
+                    IFieldStoreDao fieldStoreDao = conn.attach(IFieldStoreDao.class);
+                    fieldStoreDao.save(accountId, objectType, fieldStore.getFieldList());
+
+                    if (currentAccount == null) {
+                        IAccountCreationEvent creationEvent = new AccountCreationEvent(account);
+                        eventBus.post(creationEvent);
+                    } else {
+                        IAccountChangeEvent changeEvent = new AccountChangeEvent(account.getId(), currentAccount, account);
+                        if (changeEvent.hasChanges()) {
+                            eventBus.post(changeEvent);
+                        }
+                    }
+
+                    conn.commit();
+                } catch (Exception e) {
+                    conn.rollback();
+                    throw e;
+                }
+
+                return null;
+            }
+        });
+//
+//
+//        //accountDao.begin();
+//        try {
+//            accountDao.save(account);
+//
+//            IFieldStore fieldStore = account.getFields();
+//            fieldStoreDao.save(objectId, objectType, fieldStore.getFieldList());
+//            fieldStore.processSaveEvent();
+//
+//            account.processSaveEvent();
+//            //accountDao.commit();
+//        }
+//        catch (RuntimeException ex) {
+//            //accountDao.rollback();
+//            throw ex;
+//        }
     }
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/FieldStoreDao.java b/account/src/main/java/com/ning/billing/account/dao/FieldStoreDao.java
index baa4a99..d9f2cd2 100644
--- a/account/src/main/java/com/ning/billing/account/dao/FieldStoreDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/FieldStoreDao.java
@@ -31,13 +31,8 @@ public class FieldStoreDao implements IFieldStoreDao {
     }
 
     @Override
-    public void update(String objectId, String objectType, List<ICustomField> fields) {
-        dao.update(objectId, objectType, fields);
-    }
-
-    @Override
-    public void create(String objectId, String objectType,  List<ICustomField> fields) {
-        dao.create(objectId, objectType, fields);
+    public void save(String objectId, String objectType, List<ICustomField> entities) {
+        dao.save(objectId, objectType, entities);
     }
 
     @Override
diff --git a/account/src/main/java/com/ning/billing/account/dao/IAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/IAccountDao.java
index 814a81a..be88e39 100644
--- a/account/src/main/java/com/ning/billing/account/dao/IAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/IAccountDao.java
@@ -16,24 +16,67 @@
 
 package com.ning.billing.account.dao;
 
+import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.IAccount;
-import com.ning.billing.account.api.IAccountData;
+import com.ning.billing.account.api.user.AccountBuilder;
+import com.ning.billing.catalog.api.Currency;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.*;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
-import java.util.List;
+import java.lang.annotation.*;
+import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.util.UUID;
 
-public interface IAccountDao {
-    public IAccount createAccount(IAccountData account);
+@ExternalizedSqlViaStringTemplate3
+@RegisterMapper(AccountDao.AccountMapper.class)
+public interface IAccountDao extends IEntityDao<IAccount> {
+    @SqlQuery
+    public IAccount getAccountByKey(@Bind("externalKey") final String key);
 
-    public IAccount getAccountById(UUID uid);
+    @Override
+    @SqlUpdate
+    public void save(@AccountBinder IAccount account);
 
-    public IAccount getAccountByKey(String key);
+    public static class AccountMapper implements ResultSetMapper<IAccount> {
+        @Override
+        public IAccount map(int index, ResultSet result, StatementContext context) throws SQLException {
+            UUID id = UUID.fromString(result.getString("id"));
+            String externalKey = result.getString("external_key");
+            String email = result.getString("email");
+            String firstName = result.getString("first_name");
+            String lastName = result.getString("last_name");
+            String phone = result.getString("phone");
+            Currency currency = Currency.valueOf(result.getString("currency"));
 
-    public List<IAccount> getAccounts();
+            return new AccountBuilder(id).externalKey(externalKey).email(email)
+                                         .firstName(firstName).lastName(lastName)
+                                         .phone(phone).currency(currency).build();
+        }
+    }
 
-    public void test();
-
-    public void saveAccount(IAccount account);
-
-    public void updateAccount(IAccount account);
+    @BindingAnnotation(AccountBinder.AccountBinderFactory.class)
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.PARAMETER})
+    public @interface AccountBinder {
+        public static class AccountBinderFactory implements BinderFactory {
+            public Binder build(Annotation annotation) {
+                return new Binder<AccountBinder, Account>() {
+                    public void bind(SQLStatement q, AccountBinder bind, Account account) {
+                        q.bind("id", account.getId().toString());
+                        q.bind("externalKey", account.getExternalKey());
+                        q.bind("email", account.getEmail());
+                        q.bind("firstName", account.getFirstName());
+                        q.bind("lastName", account.getLastName());
+                        q.bind("phone", account.getPhone());
+                        q.bind("currency", account.getCurrency().toString());
+                    }
+                };
+            }
+        }
+    }
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/IAccountDaoSql.java b/account/src/main/java/com/ning/billing/account/dao/IAccountDaoSql.java
index e92c397..141544d 100644
--- a/account/src/main/java/com/ning/billing/account/dao/IAccountDaoSql.java
+++ b/account/src/main/java/com/ning/billing/account/dao/IAccountDaoSql.java
@@ -18,6 +18,7 @@ package com.ning.billing.account.dao;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.IAccount;
+import com.ning.billing.account.api.user.AccountBuilder;
 import com.ning.billing.catalog.api.Currency;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -35,7 +36,7 @@ import java.util.List;
 import java.util.UUID;
 
 @ExternalizedSqlViaStringTemplate3()
-public interface IAccountDaoSql extends Transactional<IAccountDaoSql>, CloseMe {
+public interface IAccountDaoSql extends IEntityDao<IAccount>, Transactional<IAccountDaoSql>, CloseMe {
     @SqlUpdate
     public void insertAccount(@AccountBinder IAccount account);
 
@@ -68,9 +69,9 @@ public interface IAccountDaoSql extends Transactional<IAccountDaoSql>, CloseMe {
             String phone = result.getString("phone");
             Currency currency = Currency.valueOf(result.getString("currency"));
 
-            return new Account(id).externalKey(externalKey).email(email)
-                                  .firstName(firstName).lastName(lastName)
-                                  .phone(phone).currency(currency);
+            return new AccountBuilder(id).externalKey(externalKey).email(email)
+                                         .firstName(firstName).lastName(lastName)
+                                         .phone(phone).currency(currency).build();
         }
     }
 
diff --git a/account/src/main/java/com/ning/billing/account/dao/IEntityCollectionDao.java b/account/src/main/java/com/ning/billing/account/dao/IEntityCollectionDao.java
index 8a12109..460dfac 100644
--- a/account/src/main/java/com/ning/billing/account/dao/IEntityCollectionDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/IEntityCollectionDao.java
@@ -23,14 +23,9 @@ import java.util.List;
 
 public interface IEntityCollectionDao<T extends IEntity> {
     @SqlBatch
-    public void update(@Bind("objectId") final String objectId,
-                       @Bind("objectType") final String objectType,
-                       @BindBean final List<T> entities);
-
-    @SqlBatch
-    public void create(@Bind("objectId") final String objectId,
-                       @Bind("objectType") final String objectType,
-                       @BindBean final List<T> entities);
+    public void save(@Bind("objectId") final String objectId,
+                     @Bind("objectType") final String objectType,
+                     @BindBean final List<T> entities);
 
     @SqlQuery
     public List<T> load(@Bind("objectId") final String objectId,
diff --git a/account/src/main/java/com/ning/billing/account/dao/IEntityDao.java b/account/src/main/java/com/ning/billing/account/dao/IEntityDao.java
index f56a833..7253939 100644
--- a/account/src/main/java/com/ning/billing/account/dao/IEntityDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/IEntityDao.java
@@ -19,9 +19,21 @@ package com.ning.billing.account.dao;
 import com.ning.billing.account.api.IEntity;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+
+import java.util.List;
 
 public interface IEntityDao<T extends IEntity> {
-    public void create(@BindBean final T entity);
-    public void update(@BindBean final T entity);
-    public T load(@Bind("id") final String id);
+    @SqlUpdate
+    public void save(@BindBean T entity);
+
+    @SqlQuery
+    public T getById(@Bind("id") final String id);
+
+    @SqlQuery
+    public List<T> get();
+
+    @SqlUpdate
+    public void test();
 }
diff --git a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
index cdd30c1..959ef2f 100644
--- a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
+++ b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
@@ -17,10 +17,8 @@
 package com.ning.billing.account.glue;
 
 import com.google.inject.AbstractModule;
-import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.account.api.IAccountService;
 import com.ning.billing.account.api.IAccountUserApi;
-import com.ning.billing.account.core.Engine;
+import com.ning.billing.account.api.user.AccountUserApi;
 import com.ning.billing.account.dao.AccountDao;
 import com.ning.billing.account.dao.FieldStoreDao;
 import com.ning.billing.account.dao.IAccountDao;
@@ -35,8 +33,8 @@ public class AccountModule extends AbstractModule {
     }
 
     private void installAccountCore() {
-        bind(IAccountService.class).to(Engine.class).asEagerSingleton();
-        bind(Engine.class).asEagerSingleton();
+//        bind(IAccountService.class).to(Engine.class).asEagerSingleton();
+//        bind(Engine.class).asEagerSingleton();
     }
 
     private void installAccountDao() {
diff --git a/account/src/main/java/com/ning/billing/account/glue/InjectorMagic.java b/account/src/main/java/com/ning/billing/account/glue/InjectorMagic.java
index d6cdd07..2add5ab 100644
--- a/account/src/main/java/com/ning/billing/account/glue/InjectorMagic.java
+++ b/account/src/main/java/com/ning/billing/account/glue/InjectorMagic.java
@@ -21,7 +21,6 @@ import com.google.inject.Injector;
 import com.ning.billing.account.dao.IAccountDao;
 import com.ning.billing.account.dao.IFieldStoreDao;
 import com.ning.billing.account.dao.ITagStoreDao;
-import com.ning.billing.util.eventbus.IEventBus;
 
 public class InjectorMagic {
     public static InjectorMagic instance;
@@ -61,7 +60,7 @@ public class InjectorMagic {
         return InjectorMagic.get().getInstance(ITagStoreDao.class);
     }
 
-    public static IEventBus getEventBus() {
-        return InjectorMagic.get().getInstance(IEventBus.class);
-    }
+//    public static IEventBus getEventBus() {
+//        return InjectorMagic.get().getInstance(IEventBus.class);
+//    }
 }
diff --git a/account/src/main/resources/com/ning/billing/account/dao/IFieldStoreDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/IFieldStoreDao.sql.stg
index 3722168..1e8c4c3 100644
--- a/account/src/main/resources/com/ning/billing/account/dao/IFieldStoreDao.sql.stg
+++ b/account/src/main/resources/com/ning/billing/account/dao/IFieldStoreDao.sql.stg
@@ -1,14 +1,10 @@
 group IFieldStoreDao;
 
-create() ::= <<
+save() ::= <<
   INSERT INTO custom_fields(id, object_id, object_type, field_name, field_value)
-  VALUES (:idAsString, :objectId, :objectType, :name, :value);
->>
-
-update() ::= <<
-    UPDATE custom_fields
-    SET field_value = :value
-    WHERE object_type = :objectType AND object_id = :objectId AND field_name = :name;
+  VALUES (:idAsString, :objectId, :objectType, :name, :value)
+  ON DUPLICATE KEY UPDATE
+    field_value = :value;
 >>
 
 load() ::= <<
diff --git a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
index c6adc0a..4399ef5 100644
--- a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
+++ b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
@@ -20,7 +20,8 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.account.glue.AccountModuleMock;
-import com.ning.billing.account.glue.InjectorMagic;
+import com.ning.billing.util.eventbus.EventBusService;
+import com.ning.billing.util.eventbus.IEventBusService;
 import org.apache.commons.io.IOUtils;
 import org.testng.annotations.BeforeClass;
 
@@ -29,7 +30,6 @@ import java.io.IOException;
 import static org.testng.Assert.fail;
 
 public abstract class AccountDaoTestBase {
-    private InjectorMagic injectorMagic;
     protected IFieldStoreDao fieldStoreDao;
     protected IAccountDao accountDao;
 
@@ -42,7 +42,6 @@ public abstract class AccountDaoTestBase {
             module.createDb(ddl);
 
             final Injector injector = Guice.createInjector(Stage.DEVELOPMENT, module);
-            injectorMagic = injector.getInstance(InjectorMagic.class);
 
             fieldStoreDao = injector.getInstance(IFieldStoreDao.class);
             fieldStoreDao.test();
@@ -50,7 +49,8 @@ public abstract class AccountDaoTestBase {
             accountDao = injector.getInstance(IAccountDao.class);
             accountDao.test();
 
-
+            IEventBusService busService = injector.getInstance(IEventBusService.class);
+            ((EventBusService) busService).startBus();
         }
         catch (Throwable t) {
             fail(t.toString());
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestFieldStore.java b/account/src/test/java/com/ning/billing/account/dao/TestFieldStore.java
index c5cc881..c3ef66c 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestFieldStore.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestFieldStore.java
@@ -17,6 +17,7 @@
 package com.ning.billing.account.dao;
 
 import com.ning.billing.account.api.FieldStore;
+import com.ning.billing.account.api.IFieldStore;
 import org.testng.annotations.Test;
 
 import java.util.UUID;
@@ -30,27 +31,27 @@ public class TestFieldStore extends AccountDaoTestBase {
         UUID id = UUID.randomUUID();
         String objectType = "Test widget";
 
-        FieldStore fieldStore = new FieldStore(id, objectType);
+        IFieldStore fieldStore = new FieldStore(id, objectType);
 
         String fieldName = "TestField1";
         String fieldValue = "Kitty Hawk";
         fieldStore.setValue(fieldName, fieldValue);
 
-        fieldStore.save();
+        fieldStoreDao.save(id.toString(), objectType, fieldStore.getFieldList());
 
         fieldStore = FieldStore.create(id, objectType);
-        fieldStore.load();
+        fieldStore.add(fieldStoreDao.load(id.toString(), objectType));
 
         assertEquals(fieldStore.getValue(fieldName), fieldValue);
 
         fieldValue = "Cape Canaveral";
         fieldStore.setValue(fieldName, fieldValue);
         assertEquals(fieldStore.getValue(fieldName), fieldValue);
-        fieldStore.save();
+        fieldStoreDao.save(id.toString(), objectType, fieldStore.getFieldList());
 
         fieldStore = FieldStore.create(id, objectType);
         assertEquals(fieldStore.getValue(fieldName), null);
-        fieldStore.load();
+        fieldStore.add(fieldStoreDao.load(id.toString(), objectType));
 
         assertEquals(fieldStore.getValue(fieldName), fieldValue);
     }
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
index 635af22..31f8a4f 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
@@ -18,6 +18,7 @@ package com.ning.billing.account.dao;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.IAccount;
+import com.ning.billing.account.api.user.AccountBuilder;
 import com.ning.billing.catalog.api.Currency;
 import org.testng.annotations.Test;
 
@@ -30,45 +31,46 @@ import static org.testng.Assert.*;
 public class TestSimpleAccountDao extends AccountDaoTestBase {
     private final String key = "test1234";
     private final String firstName = "Wesley";
-    private final String email = "dreadpirateroberts@therevenge.com";
+    private final String email = "me@me.com";
 
     private Account createTestAccount() {
-        Account account = Account.create();
         String thisKey = key + UUID.randomUUID().toString();
         String lastName = UUID.randomUUID().toString();
-        account.externalKey(thisKey).firstName(firstName).lastName(lastName).email(email).currency(Currency.USD);
-        return account;
+        String thisEmail = email + " " + UUID.randomUUID();
+        return new AccountBuilder().externalKey(thisKey).firstName(firstName).lastName(lastName)
+                                   .email(thisEmail).currency(Currency.USD).build();
     }
 
     public void testBasic() {
 
         IAccount a = createTestAccount();
-        accountDao.saveAccount(a);
+        accountDao.save(a);
         String key = a.getExternalKey();
 
         IAccount r = accountDao.getAccountByKey(key);
         assertNotNull(r);
         assertEquals(r.getExternalKey(), a.getExternalKey());
 
-        r = accountDao.getAccountById(r.getId());
+        r = accountDao.getById(r.getId().toString());
         assertNotNull(r);
         assertEquals(r.getExternalKey(), a.getExternalKey());
 
-        List<IAccount> all = accountDao.getAccounts();
+        List<IAccount> all = accountDao.get();
         assertNotNull(all);
         assertTrue(all.size() >= 1);
     }
 
     @Test
     public void testGetById() {
-        Account account = createTestAccount();
+        IAccount account = createTestAccount();
         UUID id = account.getId();
         String key = account.getExternalKey();
         String firstName = account.getFirstName();
         String lastName = account.getLastName();
-        account.save();
 
-        account = Account.loadAccount(id);
+        accountDao.save(account);
+
+        account = accountDao.getById(id.toString());
         assertNotNull(account);
         assertEquals(account.getId(), id);
         assertEquals(account.getExternalKey(), key);
@@ -79,18 +81,16 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
 
     @Test
     public void testCustomFields() {
-        Account account = createTestAccount();
+        IAccount account = createTestAccount();
         String fieldName = "testField1";
         String fieldValue = "testField1_value";
         account.setFieldValue(fieldName, fieldValue);
 
-        account.save();
+        accountDao.save(account);
 
-        Account thisAccount = Account.loadAccount(account.getExternalKey());
+        IAccount thisAccount = accountDao.getAccountByKey(account.getExternalKey());
         assertNotNull(thisAccount);
         assertEquals(thisAccount.getExternalKey(), account.getExternalKey());
         assertEquals(thisAccount.getFieldValue(fieldName), fieldValue);
     }
-
-
 }
diff --git a/account/src/test/java/com/ning/billing/account/glue/AccountModuleMock.java b/account/src/test/java/com/ning/billing/account/glue/AccountModuleMock.java
index 7f92ad2..54a761e 100644
--- a/account/src/test/java/com/ning/billing/account/glue/AccountModuleMock.java
+++ b/account/src/test/java/com/ning/billing/account/glue/AccountModuleMock.java
@@ -17,6 +17,7 @@
 package com.ning.billing.account.glue;
 
 import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.glue.EventBusModule;
 import org.skife.jdbi.v2.IDBI;
 
 import java.io.IOException;
@@ -33,5 +34,6 @@ public class AccountModuleMock extends AccountModule {
     protected void configure() {
         bind(IDBI.class).toInstance(helper.getDBI());
         super.configure();
+        install(new EventBusModule());
     }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java b/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
index 44466f4..1a73298 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
@@ -16,8 +16,11 @@
 
 package com.ning.billing.analytics;
 
+import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.IAccount;
+import com.ning.billing.account.api.IFieldStore;
 import com.ning.billing.catalog.api.Currency;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
 import java.util.UUID;
 
@@ -83,12 +86,27 @@ public class MockAccount implements IAccount
     }
 
     @Override
-    public boolean isNew() {
-        throw new UnsupportedOperationException();
+    public String getIdAsString() {
+        return id.toString();
     }
 
     @Override
-    public void setAsSaved() {
-        throw new UnsupportedOperationException();
+    public String getFieldValue(String fieldName) {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public void setFieldValue(String fieldName, String fieldValue) {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public IFieldStore getFields() {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public String getObjectName() {
+        return Account.OBJECT_TYPE;
     }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java
index 8c78cde..336508b 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java
@@ -20,6 +20,7 @@ import com.ning.billing.account.api.IAccount;
 import com.ning.billing.account.api.IAccountData;
 import com.ning.billing.account.api.IAccountUserApi;
 import com.ning.billing.catalog.api.Currency;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
 import java.util.List;
 import java.util.UUID;
@@ -40,6 +41,11 @@ public class MockIAccountUserApi implements IAccountUserApi
     }
 
     @Override
+    public void saveAccount(IAccount account) {
+        throw new NotImplementedException();
+    }
+
+    @Override
     public IAccount getAccountByKey(final String key)
     {
         throw new UnsupportedOperationException();
diff --git a/api/src/main/java/com/ning/billing/account/api/IAccount.java b/api/src/main/java/com/ning/billing/account/api/IAccount.java
index b141d80..5418176 100644
--- a/api/src/main/java/com/ning/billing/account/api/IAccount.java
+++ b/api/src/main/java/com/ning/billing/account/api/IAccount.java
@@ -16,6 +16,6 @@
 
 package com.ning.billing.account.api;
 
-public interface IAccount extends IAccountData, IEntity {
+public interface IAccount extends IAccountData, IEntity, ICustomizableEntity {
 
 }
diff --git a/api/src/main/java/com/ning/billing/account/api/IAccountUserApi.java b/api/src/main/java/com/ning/billing/account/api/IAccountUserApi.java
index d56dca4..28c852c 100644
--- a/api/src/main/java/com/ning/billing/account/api/IAccountUserApi.java
+++ b/api/src/main/java/com/ning/billing/account/api/IAccountUserApi.java
@@ -23,6 +23,8 @@ public interface IAccountUserApi {
 
     public IAccount createAccount(IAccountData data);
 
+    public void saveAccount(IAccount account);
+
     public IAccount getAccountByKey(String key);
 
     public IAccount getAccountById(UUID uid);
diff --git a/api/src/main/java/com/ning/billing/account/api/ICustomizableEntity.java b/api/src/main/java/com/ning/billing/account/api/ICustomizableEntity.java
index a832023..082bfbf 100644
--- a/api/src/main/java/com/ning/billing/account/api/ICustomizableEntity.java
+++ b/api/src/main/java/com/ning/billing/account/api/ICustomizableEntity.java
@@ -16,8 +16,12 @@
 
 package com.ning.billing.account.api;
 
-public interface ICustomizableEntity {
-    String getFieldValue(String fieldName);
+public interface ICustomizableEntity extends IEntity {
+    public String getFieldValue(String fieldName);
 
-    void setFieldValue(String fieldName, String fieldValue);
+    public void setFieldValue(String fieldName, String fieldValue);
+
+    public IFieldStore getFields();
+
+    public String getObjectName();
 }
diff --git a/api/src/main/java/com/ning/billing/account/api/IEntity.java b/api/src/main/java/com/ning/billing/account/api/IEntity.java
index 1797ea1..21f7132 100644
--- a/api/src/main/java/com/ning/billing/account/api/IEntity.java
+++ b/api/src/main/java/com/ning/billing/account/api/IEntity.java
@@ -20,8 +20,5 @@ import java.util.UUID;
 
 public interface IEntity {
     public UUID getId();
-
-    public boolean isNew();
-
-    public void setAsSaved();
+    public String getIdAsString();
 }
diff --git a/api/src/main/java/com/ning/billing/account/api/IFieldStore.java b/api/src/main/java/com/ning/billing/account/api/IFieldStore.java
new file mode 100644
index 0000000..9e6bf11
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/account/api/IFieldStore.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2011 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.account.api;
+
+import java.util.List;
+
+public interface IFieldStore extends IEntityCollection<ICustomField> {
+    public void setValue(String fieldName, String fieldValue);
+
+    public String getValue(String fieldName);
+
+    public List<ICustomField> getFieldList();
+
+    public void add(ICustomField field);
+
+    public void add(List<ICustomField> fields);
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/invoice/api/IInvoiceGenerated.java b/api/src/main/java/com/ning/billing/invoice/api/IInvoiceGenerated.java
new file mode 100644
index 0000000..0258b07
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/invoice/api/IInvoiceGenerated.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2011 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.invoice.api;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.eventbus.IEventBusType;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+public interface IInvoiceGenerated extends IEventBusType {
+    public UUID getInvoiceId();
+    public UUID getAccountId();
+    public BigDecimal getAmount();
+    public Currency getCurrency();
+}
\ No newline at end of file
diff --git a/catalog/src/test/resources/WeaponsHire.xml b/catalog/src/test/resources/WeaponsHire.xml
index 740a903..01d7cb4 100644
--- a/catalog/src/test/resources/WeaponsHire.xml
+++ b/catalog/src/test/resources/WeaponsHire.xml
@@ -18,7 +18,7 @@
 <!-- 
 Use cases covered so far:
 	Tiered Product (Pistol/Shotgun/Assault-Rifle)
-	Multiple change plan policies 
+	Multiple changeEvent plan policies
 	Multiple PlanAlignment (see below, trial add-on alignments and rescue discount package)
 	Product transition rules
 	Add on (Scopes, Hoster)
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
index d42cc61..2104699 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
@@ -18,6 +18,7 @@ package com.ning.billing.entitlement.api.user;
 
 import com.google.inject.Injector;
 import com.ning.billing.account.api.IAccount;
+import com.ning.billing.account.api.IFieldStore;
 import com.ning.billing.catalog.CatalogService;
 import com.ning.billing.catalog.api.*;
 import com.ning.billing.config.IEntitlementConfig;
@@ -46,6 +47,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
 import java.io.IOException;
 import java.lang.reflect.Method;
@@ -312,13 +314,28 @@ public abstract class TestUserApiBase {
             }
 
             @Override
-            public boolean isNew() {
-                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            public String getIdAsString() {
+                throw new NotImplementedException();
             }
 
             @Override
-            public void setAsSaved() {
-                //To change body of implemented methods use File | Settings | File Templates.
+            public String getFieldValue(String fieldName) {
+                throw new NotImplementedException();
+            }
+
+            @Override
+            public void setFieldValue(String fieldName, String fieldValue) {
+                throw new NotImplementedException();
+            }
+
+            @Override
+            public IFieldStore getFields() {
+                throw new NotImplementedException();
+            }
+
+            @Override
+            public String getObjectName() {
+                return null;  //To change body of implemented methods use File | Settings | File Templates.
             }
         };
         return account;
diff --git a/entitlement/src/test/resources/testInput.xml b/entitlement/src/test/resources/testInput.xml
index 740a903..01d7cb4 100644
--- a/entitlement/src/test/resources/testInput.xml
+++ b/entitlement/src/test/resources/testInput.xml
@@ -18,7 +18,7 @@
 <!-- 
 Use cases covered so far:
 	Tiered Product (Pistol/Shotgun/Assault-Rifle)
-	Multiple change plan policies 
+	Multiple changeEvent plan policies
 	Multiple PlanAlignment (see below, trial add-on alignments and rescue discount package)
 	Product transition rules
 	Add on (Scopes, Hoster)