killbill-uncached

update FieldStore to remove jdbi workaround (getIdAsString);

12/8/2011 5:28:42 PM

Changes

Details

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 1d81969..076c760 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
@@ -23,7 +23,7 @@ public abstract class CustomizableEntityBase extends EntityBase implements Custo
 
     public CustomizableEntityBase(UUID id) {
         super(id);
-        fields = StringFieldStore.create(getId(), getObjectName());
+        fields = DefaultFieldStore.create(getId(), getObjectName());
     }
 
     @Override
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
index fd7c46d..d5cc7d4 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
@@ -16,11 +16,12 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.catalog.api.Currency;
-
+import java.util.List;
 import java.util.UUID;
+import org.joda.time.DateTime;
+import com.ning.billing.catalog.api.Currency;
 
-public class DefaultAccount extends CustomizableEntityBase implements Account, Taggable {
+public class DefaultAccount extends CustomizableEntityBase implements Account {
     public final static String OBJECT_TYPE = "Account";
 
     private final String externalKey;
@@ -30,7 +31,7 @@ public class DefaultAccount extends CustomizableEntityBase implements Account, T
     private final String phone;
     private final Currency currency;
     private final int billCycleDay;
-    private final TagStore tags;
+    private final DefaultTagStore tags;
 
     public DefaultAccount(AccountData data) {
         this(UUID.randomUUID(), data.getExternalKey(), data.getEmail(), data.getName(),
@@ -48,7 +49,7 @@ public class DefaultAccount extends CustomizableEntityBase implements Account, T
         this.currency = currency;
         this.billCycleDay = billCycleDay;
 
-        this.tags = new TagStore(id, getObjectName());
+        this.tags = new DefaultTagStore(id, getObjectName());
     }
 
     @Override
@@ -90,4 +91,45 @@ public class DefaultAccount extends CustomizableEntityBase implements Account, T
     public int getBillCycleDay() {
         return billCycleDay;
     }
+
+    @Override
+    public List<Tag> getTagList() {
+        return tags.getEntityList();
+    }
+
+    @Override
+    public boolean hasTag(String tagName) {
+        return tags.containsTag(tagName);
+    }
+
+    @Override
+    public void addTag(TagDescription description, String addedBy, DateTime dateAdded) {
+        Tag tag = new DefaultTag(description, addedBy, dateAdded);
+        tags.add(tag) ;
+    }
+
+    @Override
+    public void addTags(List<Tag> tags) {
+        this.tags.add(tags);
+    }
+
+    @Override
+    public void clearTags() {
+        this.tags.clear();
+    }
+
+    @Override
+    public void removeTag(TagDescription description) {
+        tags.remove(description.getName());
+    }
+
+    @Override
+    public boolean generateInvoice() {
+        return tags.generateInvoice();
+    }
+
+    @Override
+    public boolean processPayment() {
+        return tags.processPayment();
+    }
 }
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultTagStore.java b/account/src/main/java/com/ning/billing/account/api/DefaultTagStore.java
new file mode 100644
index 0000000..151bb23
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultTagStore.java
@@ -0,0 +1,74 @@
+/*
+ * 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.UUID;
+
+public class DefaultTagStore extends EntityCollectionBase<Tag> implements TagStore {
+    public DefaultTagStore(UUID objectId, String objectType) {
+        super(objectId, objectType);
+    }
+
+    @Override
+    public String getEntityKey(Tag entity) {
+        return entity.getName();
+    }
+
+    @Override
+    /***
+     * Collates the contents of the TagStore to determine if payments should be processed
+     * @return true is no tags contraindicate payment processing
+     */
+    public boolean processPayment() {
+        for (Tag tag : entities.values()) {
+            if (!tag.getProcessPayment()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /***
+     * Collates the contents of the TagStore to determine if invoices should be generated
+     * @return true is no tags contraindicate invoice generation
+     */
+    @Override
+    public boolean generateInvoice() {
+        for (Tag tag : entities.values()) {
+            if (!tag.getGenerateInvoice()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void remove(String tagName) {
+        entities.remove(entities.get(tagName));
+    }
+
+    @Override
+    public boolean containsTag(String tagName) {
+        for (Tag tag : entities.values()) {
+            if (tag.getName() == tagName) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
\ No newline at end of file
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 375ff63..813be5f 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
@@ -33,9 +33,4 @@ public abstract class EntityBase<T> implements Entity {
     public UUID getId() {
         return id;
     }
-
-    @Override
-    public String getIdAsString() {
-        return id.toString();
-    }
 }
\ 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 b3e7552..c17cf6f 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,7 +16,9 @@
 
 package com.ning.billing.account.api;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -38,6 +40,27 @@ public abstract class EntityCollectionBase<T extends Entity> implements EntityCo
     @Override
     public abstract String getEntityKey(T entity);
 
+    @Override
+    public void add(T entity) {
+        entities.put(getEntityKey(entity), entity);
+    }
+
+    @Override
+    public void add(List<T> entities) {
+        for (T entity : entities) {
+            add(entity);
+        }
+    }
+
+    @Override
+    public void remove(T entity) {
+        entities.remove(entity);
+    }
+
+    @Override
+    public List<T> getEntityList() {
+        return new ArrayList<T>(entities.values());
+    }
 //    public void save() {
 //        IEntityCollectionDao<T> dao = getCollectionDao();
 //
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
index 1562c3c..8c4f0ab 100644
--- a/account/src/main/java/com/ning/billing/account/api/TagBuilder.java
+++ b/account/src/main/java/com/ning/billing/account/api/TagBuilder.java
@@ -16,16 +16,15 @@
 
 package com.ning.billing.account.api;
 
-import org.joda.time.DateTime;
-
 import java.util.UUID;
+import org.joda.time.DateTime;
 
 public class TagBuilder {
     private UUID id = UUID.randomUUID();
     private UUID tagDescriptionId;
-    private String description;
-    private UUID objectId;
-    private String objectType;
+    private String name;
+    private boolean processPayment;
+    private boolean generateInvoice;
     private String addedBy;
     private DateTime dateAdded;
 
@@ -39,18 +38,18 @@ public class TagBuilder {
         return this;
     }
 
-    public TagBuilder description(String description) {
-        this.description = description;
+    public TagBuilder name(String name) {
+        this.name = name;
         return this;
     }
 
-    public TagBuilder objectId(UUID objectId) {
-        this.objectId = objectId;
+    public TagBuilder processPayment(boolean processPayment) {
+        this.processPayment = processPayment;
         return this;
     }
 
-    public TagBuilder objectType(String objectType) {
-        this.objectType = objectType;
+    public TagBuilder generateInvoice(boolean generateInvoice) {
+        this.generateInvoice = generateInvoice;
         return this;
     }
 
@@ -65,6 +64,6 @@ public class TagBuilder {
     }
 
     public Tag build() {
-        return new Tag(id, tagDescriptionId, description, objectId, objectType, addedBy, dateAdded);
+        return new DefaultTag(id, tagDescriptionId, name, processPayment, generateInvoice, addedBy, dateAdded);
     }
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountDaoWrapper.java b/account/src/main/java/com/ning/billing/account/dao/AccountDaoWrapper.java
index 41f4573..1a6ed35 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountDaoWrapper.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountDaoWrapper.java
@@ -16,21 +16,27 @@
 
 package com.ning.billing.account.dao;
 
-import com.google.inject.Inject;
-import com.ning.billing.account.api.*;
-import com.ning.billing.account.api.user.AccountChangeEventDefault;
-import com.ning.billing.account.api.user.AccountCreationEventDefault;
-import com.ning.billing.util.eventbus.EventBus;
+import java.util.List;
 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 com.google.inject.Inject;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountChangeNotification;
+import com.ning.billing.account.api.AccountCreationNotification;
+import com.ning.billing.account.api.CustomField;
+import com.ning.billing.account.api.DefaultAccount;
+import com.ning.billing.account.api.FieldStore;
+import com.ning.billing.account.api.Tag;
+import com.ning.billing.account.api.user.AccountChangeEventDefault;
+import com.ning.billing.account.api.user.AccountCreationEventDefault;
+import com.ning.billing.util.eventbus.EventBus;
 
 public class AccountDaoWrapper implements AccountDao {
     private final AccountDao accountDao;
     private final FieldStoreDao fieldStoreDao;
+    private final TagStoreDao tagStoreDao;
     private final IDBI dbi; // needed for transaction support
     private final EventBus eventBus;
 
@@ -40,6 +46,7 @@ public class AccountDaoWrapper implements AccountDao {
         this.eventBus = eventBus;
         this.accountDao = dbi.onDemand(AccountDao.class);
         this.fieldStoreDao = dbi.onDemand(FieldStoreDao.class);
+        this.tagStoreDao = dbi.onDemand(TagStoreDao.class);
     }
 
     @Override
@@ -54,14 +61,17 @@ public class AccountDaoWrapper implements AccountDao {
     @Override
     public Account getById(String id) {
         Account account = accountDao.getById(id);
+
         if (account != null) {
             loadFields(account);
+            loadTags(account);
         }
+
         return account;
     }
 
     private void loadFields(Account account) {
-        List<CustomField> fields = fieldStoreDao.load(account.getId().toString(), DefaultAccount.OBJECT_TYPE);
+        List<CustomField> fields = fieldStoreDao.load(account.getId().toString(), account.getObjectName());
         account.getFields().clear();
         if (fields != null) {
             for (CustomField field : fields) {
@@ -70,6 +80,15 @@ public class AccountDaoWrapper implements AccountDao {
         }
     }
 
+    private void loadTags(Account account) {
+        List<Tag> tags = tagStoreDao.load(account.getId().toString(), account.getObjectName());
+
+        if (tags != null) {
+            account.clearTags();
+            account.addTags(tags);
+        }
+    }
+
     @Override
     public List<Account> get() {
         return accountDao.get();
@@ -97,7 +116,10 @@ public class AccountDaoWrapper implements AccountDao {
 
                     FieldStore fieldStore = account.getFields();
                     FieldStoreDao fieldStoreDao = conn.attach(FieldStoreDao.class);
-                    fieldStoreDao.save(accountId, objectType, fieldStore.getFieldList());
+                    fieldStoreDao.save(accountId, objectType, fieldStore.getEntityList());
+
+                    TagStoreDao tagStoreDao = conn.attach(TagStoreDao.class);
+                    tagStoreDao.save(accountId, objectType, account.getTagList());
 
                     if (currentAccount == null) {
                         AccountCreationNotification creationEvent = new AccountCreationEventDefault(account);
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 079aeb7..a4042b6 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
@@ -16,11 +16,60 @@
 
 package com.ning.billing.account.dao;
 
-import com.ning.billing.account.api.CustomField;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.UUID;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+import com.ning.billing.account.api.CustomField;
+import com.ning.billing.account.api.StringCustomField;
 
 @ExternalizedSqlViaStringTemplate3
-@RegisterMapper(CustomFieldMapper.class)
+@RegisterMapper(FieldStoreDao.CustomFieldMapper.class)
 public interface FieldStoreDao extends EntityCollectionDao<CustomField> {
+    @Override
+    public void save(@Bind("objectId") final String objectId,
+                     @Bind("objectType") final String objectType,
+                     @CustomFieldBinder final List<CustomField> entities);
+
+
+    public class CustomFieldMapper implements ResultSetMapper<CustomField> {
+        @Override
+        public CustomField map(int index, ResultSet result, StatementContext context) throws SQLException {
+            UUID id = UUID.fromString(result.getString("id"));
+            String fieldName = result.getString("field_name");
+            String fieldValue = result.getString("field_value");
+            return new StringCustomField(id, fieldName, fieldValue);
+        }
+    }
+
+    @BindingAnnotation(CustomFieldBinder.CustomFieldBinderFactory.class)
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.PARAMETER})
+    public @interface CustomFieldBinder {
+        public static class CustomFieldBinderFactory implements BinderFactory {
+            public Binder build(Annotation annotation) {
+                return new Binder<CustomFieldBinder, CustomField>() {
+                    public void bind(SQLStatement q, CustomFieldBinder bind, CustomField customField) {
+                        q.bind("id", customField.getId().toString());
+                        q.bind("fieldName", customField.getName());
+                        q.bind("fieldValue", customField.getValue());
+                    }
+                };
+            }
+        }
+    }
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/TagDescriptionMapper.java b/account/src/main/java/com/ning/billing/account/dao/TagDescriptionMapper.java
index 483ba6a..545e22e 100644
--- a/account/src/main/java/com/ning/billing/account/dao/TagDescriptionMapper.java
+++ b/account/src/main/java/com/ning/billing/account/dao/TagDescriptionMapper.java
@@ -16,8 +16,8 @@
 
 package com.ning.billing.account.dao;
 
-import com.ning.billing.account.api.TagDescription;
 import org.skife.jdbi.v2.BeanMapper;
+import com.ning.billing.account.api.TagDescription;
 
 public class TagDescriptionMapper extends BeanMapper<TagDescription> {
     public TagDescriptionMapper() {
diff --git a/account/src/main/java/com/ning/billing/account/dao/TagStoreDao.java b/account/src/main/java/com/ning/billing/account/dao/TagStoreDao.java
index f463b40..ea1ee98 100644
--- a/account/src/main/java/com/ning/billing/account/dao/TagStoreDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/TagStoreDao.java
@@ -16,11 +16,47 @@
 
 package com.ning.billing.account.dao;
 
-import com.ning.billing.account.api.Tag;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+import org.skife.jdbi.v2.sqlobject.SqlBatch;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+import com.ning.billing.account.api.DefaultTag;
+import com.ning.billing.account.api.Tag;
 
 @ExternalizedSqlViaStringTemplate3
 @RegisterMapper(TagDescriptionMapper.class)
 public interface TagStoreDao extends EntityCollectionDao<Tag> {
-}
+    @Override
+    @SqlBatch
+    public void save(@Bind("objectId") final String objectId,
+                     @Bind("objectType") final String objectType,
+                     @TagBinder final List<Tag> entities);
+
+    @BindingAnnotation(TagBinder.TagBinderFactory.class)
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.PARAMETER})
+    public @interface TagBinder {
+        public static class TagBinderFactory implements BinderFactory {
+            public Binder build(Annotation annotation) {
+                return new Binder<TagBinder, DefaultTag>() {
+                    public void bind(SQLStatement q, TagBinder bind, DefaultTag tag) {
+                        q.bind("id", tag.getId().toString());
+                        q.bind("tagDescriptionId", tag.getTagDescriptionId().toString());
+                        q.bind("dateAdded", tag.getDateAdded().toDate());
+                        q.bind("addedBy", tag.getAddedBy());
+                    }
+                };
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/account/src/main/resources/com/ning/billing/account/dao/TagDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/TagDao.sql.stg
index 3a961a9..13c6dde 100644
--- a/account/src/main/resources/com/ning/billing/account/dao/TagDao.sql.stg
+++ b/account/src/main/resources/com/ning/billing/account/dao/TagDao.sql.stg
@@ -11,7 +11,4 @@ update() ::= <<
 load() ::= <<
 
 >>
-;
-
-
-  id, tag_description_id, object_id, date_added, added_by
\ No newline at end of file
+;
\ No newline at end of file
diff --git a/account/src/main/resources/com/ning/billing/account/dao/TagStoreDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/TagStoreDao.sql.stg
new file mode 100644
index 0000000..8520d6c
--- /dev/null
+++ b/account/src/main/resources/com/ning/billing/account/dao/TagStoreDao.sql.stg
@@ -0,0 +1,20 @@
+group TagStoreDao;
+
+save() ::= <<
+  INSERT INTO tags(id, tag_description_id, object_id, object_type, date_added, added_by)
+  VALUES (:id, :tagDescriptionId, :objectId, :objectType, :dateAdded, :addedBy)
+  ON DUPLICATE KEY UPDATE
+    tag_description_id = :tagDescriptionId, object_id = :objectId, object_type = :objectType,
+    date_added = :dateAdded, added_by = :addedBy;
+>>
+
+load() ::= <<
+    SELECT id, tag_description_id, object_id, object_type, date_added, added_by
+    FROM tags
+    WHERE object_id = :objectId AND object_type = :objectType;
+>>
+
+test() ::= <<
+  SELECT 1 FROM tags;
+>>
+;
\ No newline at end of file
diff --git a/account/src/main/resources/com/ning/billing/account/ddl.sql b/account/src/main/resources/com/ning/billing/account/ddl.sql
index 55dff4e..f925467 100644
--- a/account/src/main/resources/com/ning/billing/account/ddl.sql
+++ b/account/src/main/resources/com/ning/billing/account/ddl.sql
@@ -43,6 +43,7 @@ CREATE TABLE tags (
   id char(36) NOT NULL,
   tag_description_id char(36) NOT NULL,
   object_id char(36) NOT NULL,
+  object_type varchar(30) NOT NULL,
   date_added datetime NOT NULL,
   added_by varchar(50) NOT NULL,
   PRIMARY KEY(id)
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 facfb69..fa110ed 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
@@ -16,11 +16,10 @@
 
 package com.ning.billing.account.dao;
 
-import com.ning.billing.account.api.FieldStore;
-import com.ning.billing.account.api.StringFieldStore;
-import org.testng.annotations.Test;
-
 import java.util.UUID;
+import org.testng.annotations.Test;
+import com.ning.billing.account.api.DefaultFieldStore;
+import com.ning.billing.account.api.FieldStore;
 
 import static org.testng.Assert.assertEquals;
 
@@ -31,15 +30,15 @@ public class TestFieldStore extends AccountDaoTestBase {
         UUID id = UUID.randomUUID();
         String objectType = "Test widget";
 
-        FieldStore fieldStore = new StringFieldStore(id, objectType);
+        FieldStore fieldStore = new DefaultFieldStore(id, objectType);
 
         String fieldName = "TestField1";
         String fieldValue = "Kitty Hawk";
         fieldStore.setValue(fieldName, fieldValue);
 
-        fieldStoreDao.save(id.toString(), objectType, fieldStore.getFieldList());
+        fieldStoreDao.save(id.toString(), objectType, fieldStore.getEntityList());
 
-        fieldStore = StringFieldStore.create(id, objectType);
+        fieldStore = DefaultFieldStore.create(id, objectType);
         fieldStore.add(fieldStoreDao.load(id.toString(), objectType));
 
         assertEquals(fieldStore.getValue(fieldName), fieldValue);
@@ -47,9 +46,9 @@ public class TestFieldStore extends AccountDaoTestBase {
         fieldValue = "Cape Canaveral";
         fieldStore.setValue(fieldName, fieldValue);
         assertEquals(fieldStore.getValue(fieldName), fieldValue);
-        fieldStoreDao.save(id.toString(), objectType, fieldStore.getFieldList());
+        fieldStoreDao.save(id.toString(), objectType, fieldStore.getEntityList());
 
-        fieldStore = StringFieldStore.create(id, objectType);
+        fieldStore = DefaultFieldStore.create(id, objectType);
         assertEquals(fieldStore.getValue(fieldName), null);
         fieldStore.add(fieldStoreDao.load(id.toString(), objectType));
 
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 88e8c77..ed308ae 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
@@ -16,16 +16,21 @@
 
 package com.ning.billing.account.dao;
 
+import java.util.List;
+import java.util.UUID;
+import org.joda.time.DateTime;
+import org.testng.annotations.Test;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.DefaultAccount;
+import com.ning.billing.account.api.DefaultTagDescription;
+import com.ning.billing.account.api.Tag;
+import com.ning.billing.account.api.TagDescription;
 import com.ning.billing.account.api.user.AccountBuilder;
 import com.ning.billing.catalog.api.Currency;
-import org.testng.annotations.Test;
-
-import java.util.List;
-import java.util.UUID;
 
-import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
 
 @Test(groups = {"account-dao"})
 public class TestSimpleAccountDao extends AccountDaoTestBase {
@@ -96,4 +101,26 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
         assertEquals(thisAccount.getExternalKey(), account.getExternalKey());
         assertEquals(thisAccount.getFieldValue(fieldName), fieldValue);
     }
+
+    @Test
+    public void testTags() {
+        Account account = createTestAccount();
+        TagDescription description = new DefaultTagDescription("Test Tag", "For testing only", true, true, "Test System", new DateTime());
+        String addedBy = "testTags()";
+        DateTime dateAdded = new DateTime();
+        account.addTag(description, addedBy, dateAdded);
+        assertEquals(account.getTagList().size(), 1);
+        accountDao.save(account);
+
+        Account thisAccount = accountDao.getById(account.getId().toString());
+        List<Tag> tagList = thisAccount.getTagList();
+        assertEquals(tagList.size(), 1);
+        Tag tag = tagList.get(0);
+        assertEquals(tag.getName(), description.getName());
+        assertEquals(tag.getGenerateInvoice(), description.getGenerateInvoice());
+        assertEquals(tag.getProcessPayment(), description.getProcessPayment());
+        assertEquals(tag.getTagDescriptionId(), description.getId());
+        assertEquals(tag.getAddedBy(), addedBy);
+        assertEquals(tag.getDateAdded(), dateAdded);
+    }
 }
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 56c5ce0..7bb16fc 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
@@ -16,15 +16,11 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.DefaultAccount;
-import com.ning.billing.account.api.FieldStore;
-import com.ning.billing.catalog.api.Currency;
-import sun.reflect.generics.reflectiveObjects.NotImplementedException;
-
 import java.util.UUID;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.catalog.api.Currency;
 
-public class MockAccount implements Account
+public class MockAccount implements AccountData
 {
     private final UUID id;
     private final String accountKey;
@@ -82,29 +78,4 @@ public class MockAccount implements Account
     {
         return id;
     }
-
-    @Override
-    public String getIdAsString() {
-        return id.toString();
-    }
-
-    @Override
-    public String getFieldValue(String fieldName) {
-        throw new NotImplementedException();
-    }
-
-    @Override
-    public void setFieldValue(String fieldName, String fieldValue) {
-        throw new NotImplementedException();
-    }
-
-    @Override
-    public FieldStore getFields() {
-        throw new NotImplementedException();
-    }
-
-    @Override
-    public String getObjectName() {
-        return DefaultAccount.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 d11f4e9..4982fe2 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockIAccountUserApi.java
@@ -16,18 +16,19 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountData;
-import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.catalog.api.Currency;
 import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
 import java.util.List;
 import java.util.UUID;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.account.api.DefaultAccount;
+import com.ning.billing.catalog.api.Currency;
 
 public class MockIAccountUserApi implements AccountUserApi
 {
-    private final MockAccount account;
+    private final AccountData account;
 
     public MockIAccountUserApi(final String accountKey, final Currency currency)
     {
@@ -54,7 +55,7 @@ public class MockIAccountUserApi implements AccountUserApi
     @Override
     public Account getAccountById(final UUID uid)
     {
-        return account;
+        return new DefaultAccount(account);
     }
 
     @Override
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
index 475353d..47ce151 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
@@ -16,19 +16,18 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.account.api.Account;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.joda.time.DateTime;
+import com.ning.billing.account.api.AccountData;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import org.joda.time.DateTime;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
 
 public class MockIEntitlementUserApi implements EntitlementUserApi
 {
@@ -94,7 +93,7 @@ public class MockIEntitlementUserApi implements EntitlementUserApi
     }
 
     @Override
-    public SubscriptionBundle createBundleForAccount(final Account account, final String bundleKey) throws EntitlementUserApiException
+    public SubscriptionBundle createBundleForAccount(final AccountData account, final String bundleKey) throws EntitlementUserApiException
     {
         throw new UnsupportedOperationException();
     }
diff --git a/api/src/main/java/com/ning/billing/account/api/Account.java b/api/src/main/java/com/ning/billing/account/api/Account.java
index d224fac..9efce90 100644
--- a/api/src/main/java/com/ning/billing/account/api/Account.java
+++ b/api/src/main/java/com/ning/billing/account/api/Account.java
@@ -16,6 +16,6 @@
 
 package com.ning.billing.account.api;
 
-public interface Account extends AccountData, Entity, CustomizableEntity {
+public interface Account extends AccountData, CustomizableEntity, Taggable {
 
 }
diff --git a/api/src/main/java/com/ning/billing/account/api/AccountData.java b/api/src/main/java/com/ning/billing/account/api/AccountData.java
index fe54598..b0f7dc4 100644
--- a/api/src/main/java/com/ning/billing/account/api/AccountData.java
+++ b/api/src/main/java/com/ning/billing/account/api/AccountData.java
@@ -18,7 +18,7 @@ package com.ning.billing.account.api;
 
 import com.ning.billing.catalog.api.Currency;
 
-public interface AccountData {
+public interface AccountData extends Entity{
 
     public String getExternalKey();
 
diff --git a/api/src/main/java/com/ning/billing/account/api/Entity.java b/api/src/main/java/com/ning/billing/account/api/Entity.java
index 1d489ed..a804ade 100644
--- a/api/src/main/java/com/ning/billing/account/api/Entity.java
+++ b/api/src/main/java/com/ning/billing/account/api/Entity.java
@@ -20,5 +20,4 @@ import java.util.UUID;
 
 public interface Entity {
     public UUID getId();
-    public String getIdAsString();
 }
diff --git a/api/src/main/java/com/ning/billing/account/api/EntityCollection.java b/api/src/main/java/com/ning/billing/account/api/EntityCollection.java
index c069629..7730656 100644
--- a/api/src/main/java/com/ning/billing/account/api/EntityCollection.java
+++ b/api/src/main/java/com/ning/billing/account/api/EntityCollection.java
@@ -16,7 +16,18 @@
 
 package com.ning.billing.account.api;
 
+import java.util.List;
+
 public interface EntityCollection<T extends Entity> {
     public String getEntityKey(T entity);
+
     public void clear();
+
+    public void add(T entity);
+
+    public void add(List<T> entities);
+
+    public void remove(T entity);
+
+    public List<T> getEntityList();
 }
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/account/api/FieldStore.java b/api/src/main/java/com/ning/billing/account/api/FieldStore.java
index b5ffdbd..1946817 100644
--- a/api/src/main/java/com/ning/billing/account/api/FieldStore.java
+++ b/api/src/main/java/com/ning/billing/account/api/FieldStore.java
@@ -16,16 +16,8 @@
 
 package com.ning.billing.account.api;
 
-import java.util.List;
-
 public interface FieldStore extends EntityCollection<CustomField> {
     public void setValue(String fieldName, String fieldValue);
 
     public String getValue(String fieldName);
-
-    public List<CustomField> getFieldList();
-
-    public void add(CustomField field);
-
-    public void add(List<CustomField> fields);
 }
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/account/api/TagDescription.java b/api/src/main/java/com/ning/billing/account/api/TagDescription.java
new file mode 100644
index 0000000..634a5ba
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/account/api/TagDescription.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+public interface TagDescription extends Entity {
+    String getName();
+
+    String getCreatedBy();
+
+    DateTime getCreationDate();
+
+    String getDescription();
+
+    boolean getGenerateInvoice();
+
+    boolean getProcessPayment();
+}
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
index 0a46e8c..10f8591 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
@@ -16,13 +16,12 @@
 
 package com.ning.billing.entitlement.api.user;
 
-import com.ning.billing.account.api.Account;
-import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.PhaseType;
-import org.joda.time.DateTime;
-
 import java.util.List;
 import java.util.UUID;
+import org.joda.time.DateTime;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
 
 
 public interface EntitlementUserApi {
@@ -37,7 +36,7 @@ public interface EntitlementUserApi {
 
     public List<Subscription> getSubscriptionsForKey(String bundleKey);
 
-    public SubscriptionBundle createBundleForAccount(Account account, String bundleKey)
+    public SubscriptionBundle createBundleForAccount(AccountData account, String bundleKey)
         throws EntitlementUserApiException;
 
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
index dd37d2e..135ce3e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
@@ -16,19 +16,24 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.List;
+import java.util.UUID;
+import org.joda.time.DateTime;
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
-import com.ning.billing.account.api.Account;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-
-import java.util.List;
-import java.util.UUID;
 
 public class DefaultEntitlementUserApi implements EntitlementUserApi {
 
@@ -73,7 +78,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
     }
 
     @Override
-    public SubscriptionBundle createBundleForAccount(Account account, String bundleName)
+    public SubscriptionBundle createBundleForAccount(AccountData account, String bundleName)
     throws EntitlementUserApiException {
         SubscriptionBundleData bundle = new SubscriptionBundleData(bundleName, account.getId());
         return dao.createSubscriptionBundle(bundle);
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 e2fe2f3..3a245d1 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
@@ -16,11 +16,28 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.List;
+import java.util.UUID;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
 import com.google.inject.Injector;
-import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.FieldStore;
+import com.ning.billing.account.api.AccountData;
 import com.ning.billing.catalog.DefaultCatalogService;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Catalog;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.TimeUnit;
 import com.ning.billing.config.EntitlementConfig;
 import com.ning.billing.entitlement.api.ApiTestListener;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
@@ -38,22 +55,11 @@ import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.eventbus.DefaultEventBusService;
 import com.ning.billing.util.eventbus.EventBusService;
-import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
 
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.List;
-import java.util.UUID;
-
-import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
 
 
 public abstract class TestUserApiBase {
@@ -71,7 +77,7 @@ public abstract class TestUserApiBase {
     protected ClockMock clock;
     protected EventBusService busService;
 
-    protected Account account;
+    protected AccountData accountData;
     protected Catalog catalog;
     protected ApiTestListener testListener;
     protected SubscriptionBundle bundle;
@@ -127,8 +133,8 @@ public abstract class TestUserApiBase {
     protected abstract Injector getInjector();
 
     private void init() throws EntitlementUserApiException {
-        account = getAccount();
-        assertNotNull(account);
+        accountData = getAccountData();
+        assertNotNull(accountData);
 
         catalog = catalogService.getCatalog();
         assertNotNull(catalog);
@@ -152,7 +158,7 @@ public abstract class TestUserApiBase {
         ((MockEntitlementDao) dao).reset();
         try {
             busService.getEventBus().register(testListener);
-            bundle = entitlementApi.createBundleForAccount(account, "myDefaultBundle");
+            bundle = entitlementApi.createBundleForAccount(accountData, "myDefaultBundle");
         } catch (Exception e) {
             Assert.fail(e.getMessage());
         }
@@ -275,8 +281,8 @@ public abstract class TestUserApiBase {
         return result;
     }
 
-    protected Account getAccount() {
-        Account account = new Account() {
+    protected AccountData getAccountData() {
+        AccountData accountData = new AccountData() {
             private final UUID id = UUID.randomUUID();
 
             @Override
@@ -314,31 +320,8 @@ public abstract class TestUserApiBase {
             public UUID getId() {
                 return id;
             }
-
-            @Override
-            public String getIdAsString() {
-                return id.toString();
-            }
-
-            @Override
-            public String getFieldValue(String fieldName) {
-                return null;
-            }
-
-            @Override
-            public void setFieldValue(String fieldName, String fieldValue) {}
-
-            @Override
-            public FieldStore getFields() {
-                return null;  //To change body of implemented methods use File | Settings | File Templates.
-            }
-
-            @Override
-            public String getObjectName() {
-                return null;  //To change body of implemented methods use File | Settings | File Templates.
-            }
         };
-        return account;
+        return accountData;
     }