killbill-memoizeit

analytics: more work, saving the current tree Signed-off-by:

4/3/2013 9:33:23 PM

Details

diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
index f7e5e6b..82b371f 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
@@ -28,10 +28,12 @@ import com.ning.billing.commons.locker.GlobalLock;
 import com.ning.billing.commons.locker.GlobalLocker;
 import com.ning.billing.commons.locker.mysql.MySqlGlobalLocker;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessAccountDao;
+import com.ning.billing.osgi.bundles.analytics.dao.BusinessFieldDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoiceDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoicePaymentDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessOverdueStatusDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessSubscriptionTransitionDao;
+import com.ning.billing.osgi.bundles.analytics.dao.BusinessTagDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.UserType;
@@ -51,6 +53,8 @@ public class AnalyticsListener implements OSGIKillbillEventHandler {
     private final BusinessInvoiceDao binDao;
     private final BusinessInvoicePaymentDao bipDao;
     private final BusinessOverdueStatusDao bosDao;
+    private final BusinessFieldDao bFieldDao;
+    private final BusinessTagDao bTagDao;
     private final GlobalLocker locker;
 
     public AnalyticsListener(final OSGIKillbillLogService logService,
@@ -63,6 +67,8 @@ public class AnalyticsListener implements OSGIKillbillEventHandler {
         this.binDao = new BusinessInvoiceDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao);
         this.bipDao = new BusinessInvoicePaymentDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao, binDao);
         this.bosDao = new BusinessOverdueStatusDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+        this.bFieldDao = new BusinessFieldDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+        this.bTagDao = new BusinessTagDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
 
         this.locker = new MySqlGlobalLocker(osgiKillbillDataSource.getDataSource());
     }
@@ -147,7 +153,7 @@ public class AnalyticsListener implements OSGIKillbillEventHandler {
         updateWithAccountLock(killbillEvent, new Callable<Void>() {
             @Override
             public Void call() throws Exception {
-                bosDao.update(killbillEvent.getObjectType(), killbillEvent.getObjectId(), callContext);
+                bosDao.update(killbillEvent.getAccountId(), killbillEvent.getObjectType(), callContext);
                 return null;
             }
         });
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java
index f6d9d81..ba3c625 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java
@@ -16,25 +16,12 @@
 
 package com.ning.billing.osgi.bundles.analytics.api.user;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.UUID;
 
-import javax.annotation.Nullable;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.osgi.service.log.LogService;
 
 import com.ning.billing.ObjectType;
-import com.ning.billing.account.api.Account;
-import com.ning.billing.analytics.api.TimeSeriesData;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.junction.api.Blockable.Type;
 import com.ning.billing.osgi.bundles.analytics.AnalyticsRefreshException;
 import com.ning.billing.osgi.bundles.analytics.BusinessAnalyticsBase;
 import com.ning.billing.osgi.bundles.analytics.api.BusinessAccount;
@@ -47,329 +34,92 @@ import com.ning.billing.osgi.bundles.analytics.api.BusinessSubscriptionTransitio
 import com.ning.billing.osgi.bundles.analytics.api.BusinessTag;
 import com.ning.billing.osgi.bundles.analytics.dao.AnalyticsDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessAccountDao;
+import com.ning.billing.osgi.bundles.analytics.dao.BusinessFieldDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoiceDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoicePaymentDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessOverdueStatusDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessSubscriptionTransitionDao;
 import com.ning.billing.osgi.bundles.analytics.dao.BusinessTagDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessAccountModelDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessAccountTagModelDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceModelDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoicePaymentModelDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessOverdueStatusModelDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessSubscriptionTransitionModelDao;
-import com.ning.billing.payment.api.Payment;
-import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.InternalCallContext;
-import com.ning.billing.util.callcontext.InternalCallContextFactory;
-import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.callcontext.TenantContext;
-import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
-import com.ning.billing.util.svcapi.payment.PaymentInternalApi;
-import com.ning.billing.util.svcapi.tag.TagInternalApi;
-import com.ning.billing.util.tag.Tag;
-import com.ning.billing.util.tag.TagDefinition;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillAPI;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillDataSource;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillLogService;
 
 public class AnalyticsUserApi extends BusinessAnalyticsBase {
 
-    private static final Logger log = LoggerFactory.getLogger(AnalyticsUserApi.class);
-
     private final AnalyticsDao analyticsDao;
-    private final BusinessSubscriptionTransitionDao bstDao;
     private final BusinessAccountDao bacDao;
-    private final BusinessInvoiceDao invoiceDao;
-    private final BusinessOverdueStatusDao bosDao;
+    private final BusinessSubscriptionTransitionDao bstDao;
+    private final BusinessInvoiceDao binDao;
     private final BusinessInvoicePaymentDao bipDao;
-    private final BusinessTagDao tagDao;
-    private final EntitlementInternalApi entitlementInternalApi;
-    private final PaymentInternalApi paymentApi;
-    private final TagInternalApi tagInternalApi;
-    private final InternalCallContextFactory internalCallContextFactory;
-
-    public AnalyticsUserApi(final AnalyticsDao analyticsDao,
-                            final BusinessSubscriptionTransitionDao bstDao,
-                            final BusinessAccountDao bacDao,
-                            final BusinessInvoiceDao invoiceDao,
-                            final BusinessOverdueStatusDao bosDao,
-                            final BusinessInvoicePaymentDao bipDao,
-                            final BusinessTagDao tagDao,
-                            final EntitlementInternalApi entitlementInternalApi,
-                            final PaymentInternalApi paymentApi,
-                            final TagInternalApi tagInternalApi,
-                            final InternalCallContextFactory internalCallContextFactory) {
-        super();
-
-        this.analyticsDao = analyticsDao;
-        this.bstDao = bstDao;
-        this.bacDao = bacDao;
-        this.invoiceDao = invoiceDao;
-        this.bosDao = bosDao;
-        this.bipDao = bipDao;
-        this.tagDao = tagDao;
-        this.entitlementInternalApi = entitlementInternalApi;
-        this.paymentApi = paymentApi;
-        this.tagInternalApi = tagInternalApi;
-        this.internalCallContextFactory = internalCallContextFactory;
+    private final BusinessOverdueStatusDao bosDao;
+    private final BusinessFieldDao bFieldDao;
+    private final BusinessTagDao bTagDao;
+
+    public AnalyticsUserApi(final OSGIKillbillLogService logService,
+                            final OSGIKillbillAPI osgiKillbillAPI,
+                            final OSGIKillbillDataSource osgiKillbillDataSource) {
+        super(logService, osgiKillbillAPI);
+        this.analyticsDao = new AnalyticsDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+        this.bacDao = new BusinessAccountDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+        this.bstDao = new BusinessSubscriptionTransitionDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+        this.binDao = new BusinessInvoiceDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao);
+        this.bipDao = new BusinessInvoicePaymentDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao, binDao);
+        this.bosDao = new BusinessOverdueStatusDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+        this.bFieldDao = new BusinessFieldDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+        this.bTagDao = new BusinessTagDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
     }
 
-    public BusinessSnapshot getBusinessSnapshot(final Account account, final TenantContext context) {
+    public BusinessSnapshot getBusinessSnapshot(final UUID accountId, final TenantContext context) {
         // Find account
-        final BusinessAccount businessAccount = getAccountByKey(account.getExternalKey(), context);
+        final BusinessAccount businessAccount = analyticsDao.getAccountById(accountId, context);
 
         // Find all transitions for all bundles for that account, and associated overdue statuses
-        final List<SubscriptionBundle> bundles = entitlementInternalApi.getBundlesForAccount(account.getId(), context);
-        final Collection<BusinessSubscriptionTransition> businessSubscriptionTransitions = new ArrayList<BusinessSubscriptionTransition>();
-        final Collection<BusinessOverdueStatus> businessOverdueStatuses = new ArrayList<BusinessOverdueStatus>();
-        for (final SubscriptionBundle bundle : bundles) {
-            businessSubscriptionTransitions.addAll(getTransitionsForBundle(bundle.getExternalKey(), context));
-            businessOverdueStatuses.addAll(getOverdueStatusesForBundle(bundle.getExternalKey(), context));
-        }
+        final Collection<BusinessSubscriptionTransition> businessSubscriptionTransitions = analyticsDao.getSubscriptionTransitionsForAccount(accountId, context);
+        final Collection<BusinessOverdueStatus> businessOverdueStatuses = analyticsDao.getOverdueStatusesForAccount(accountId, context);
 
         // Find all invoices for that account
-        final Collection<BusinessInvoice> businessInvoices = getInvoicesForAccount(account.getExternalKey(), context);
+        final Collection<BusinessInvoice> businessInvoices = analyticsDao.getInvoicesForAccount(accountId, context);
 
         // Find all payments for that account
-        final Collection<BusinessInvoicePayment> businessInvoicePayments = getInvoicePaymentsForAccount(account.getExternalKey(), context);
+        final Collection<BusinessInvoicePayment> businessInvoicePayments = analyticsDao.getInvoicePaymentsForAccount(accountId, context);
 
         // Find all tags for that account
-        // TODO add other tag types
-        final Collection<BusinessTag> businessTags = getTagsForAccount(account.getExternalKey(), context);
-
-        // TODO find custom fields
-        final Collection<BusinessField> businessFields = ImmutableList.<BusinessField>of();
-
-        return new BusinessSnapshot(businessAccount, businessSubscriptionTransitions, businessInvoices, businessInvoicePayments,
-                                    businessOverdueStatuses, businessTags, businessFields);
+        final Collection<BusinessTag> businessTags = analyticsDao.getTagsForAccount(accountId, context);
+
+        // Find all fields for that account
+        final Collection<BusinessField> businessFields = analyticsDao.getFieldsForAccount(accountId, context);
+
+        return new BusinessSnapshot(businessAccount,
+                                    businessSubscriptionTransitions,
+                                    businessInvoices,
+                                    businessInvoicePayments,
+                                    businessOverdueStatuses,
+                                    businessTags,
+                                    businessFields);
     }
 
-    public BusinessAccount getAccountByKey(final String accountKey, final TenantContext context) {
-        final BusinessAccountModelDao accountByKey = analyticsDao.getAccountByKey(accountKey, context);
-        if (accountByKey == null) {
-            return null;
-        } else {
-            return new BusinessAccount(accountByKey);
-        }
-    }
+    public void rebuildAnalyticsForAccount(final UUID accountId, final CallContext context) throws AnalyticsRefreshException {
+        logService.log(LogService.LOG_INFO, "Starting rebuild of Analytics for account " + accountId);
 
-    public List<BusinessSubscriptionTransition> getTransitionsForBundle(final String externalKey, final TenantContext context) {
-        final List<BusinessSubscriptionTransitionModelDao> transitionsByKey = analyticsDao.getSubscriptionTransitionsByBundleExternalKey(externalKey, context);
-        return ImmutableList.<BusinessSubscriptionTransition>copyOf(Collections2.transform(transitionsByKey, new Function<BusinessSubscriptionTransitionModelDao, BusinessSubscriptionTransition>() {
-
-            public BusinessSubscriptionTransition apply(@Nullable final BusinessSubscriptionTransitionModelDao input) {
-                return new BusinessSubscriptionTransition(input);
-            }
-        }));
-    }
+        // Refresh payments. This will automatically trigger a refresh of invoices and account
+        bipDao.update(accountId, context);
 
-    public List<BusinessInvoice> getInvoicesForAccount(final String accountKey, final TenantContext context) {
-        final InternalTenantContext internalTenantContext = context;
-        final List<BusinessInvoiceModelDao> invoicesByKey = analyticsDao.getInvoicesByKey(accountKey, internalTenantContext);
-        return ImmutableList.<BusinessInvoice>copyOf(Collections2.transform(invoicesByKey, new Function<BusinessInvoiceModelDao, BusinessInvoice>() {
-
-            public BusinessInvoice apply(@Nullable final BusinessInvoiceModelDao input) {
-                return new BusinessInvoice(input, input == null ? null : analyticsDao.getInvoiceItemsForInvoice(input.getInvoiceId().toString(), internalTenantContext));
-            }
-        }));
-    }
-
-    public List<BusinessInvoicePayment> getInvoicePaymentsForAccount(final String accountKey, final TenantContext context) {
-        final List<BusinessInvoicePaymentModelDao> invoicePaymentsForAccountByKey = analyticsDao.getInvoicePaymentsForAccountByKey(accountKey, context);
-        return ImmutableList.<BusinessInvoicePayment>copyOf(Collections2.transform(invoicePaymentsForAccountByKey, new Function<BusinessInvoicePaymentModelDao, BusinessInvoicePayment>() {
-
-            public BusinessInvoicePayment apply(@Nullable final BusinessInvoicePaymentModelDao input) {
-                return new BusinessInvoicePayment(input);
-            }
-        }));
-    }
-
-    public List<BusinessOverdueStatus> getOverdueStatusesForBundle(final String externalKey, final TenantContext context) {
-        final List<BusinessOverdueStatusModelDao> overdueStatusesForBundleByKey = analyticsDao.getOverdueStatusesForBundleByKey(externalKey, context);
-        return ImmutableList.<BusinessOverdueStatus>copyOf(Collections2.transform(overdueStatusesForBundleByKey, new Function<BusinessOverdueStatusModelDao, BusinessOverdueStatus>() {
-
-            public BusinessOverdueStatus apply(@Nullable final BusinessOverdueStatusModelDao input) {
-                return new BusinessOverdueStatus(input);
-            }
-        }));
-    }
-
-    public List<BusinessTag> getTagsForAccount(final String accountKey, final TenantContext context) {
-        final List<BusinessAccountTagModelDao> tagsForAccount = analyticsDao.getTagsForAccount(accountKey, context);
-        return ImmutableList.<BusinessTag>copyOf(Collections2.transform(tagsForAccount, new Function<BusinessAccountTagModelDao, BusinessTag>() {
-
-            public BusinessTag apply(@Nullable final BusinessAccountTagModelDao input) {
-                return new BusinessTag(input);
-            }
-        }));
-    }
-
-    public TimeSeriesData getAccountsCreatedOverTime(final TenantContext context) {
-        return analyticsDao.getAccountsCreatedOverTime(context);
-    }
-
-    public TimeSeriesData getSubscriptionsCreatedOverTime(final String productType, final String slug, final TenantContext context) {
-        return analyticsDao.getSubscriptionsCreatedOverTime(productType, slug, context);
-    }
+        // Refresh BST
+        bstDao.update(accountId, context);
 
-    public void rebuildAnalyticsForAccount(final Account account, final CallContext context) throws AnalyticsRefreshException {
-        // Update the BAC row
-        bacDao.update(account.getId(), context);
+        for (final ObjectType objectType : ObjectType.values()) {
+            // Refresh BOS
+            bosDao.update(accountId, objectType, context);
 
-        // Update BST for all bundles
-        final Set<UUID> bundleIds = updateBST(account, context);
+            // Refresh fields
+            bFieldDao.update(accountId, objectType, context);
 
-        // Update BIN, BII, ... for all invoices
-        invoiceDao.update(account.getId(), context);
-
-        // Update BIP for all invoices
-        try {
-            updateBIP(account, context);
-        } catch (PaymentApiException e) {
-            // Log and ignore
-            log.warn(e.toString());
-        }
-
-        // Update BOS for all bundles (only blockable supported today)
-        // TODO: support other blockables
-        for (final UUID bundleId : bundleIds) {
-            bosDao.overdueStatusChanged(Type.SUBSCRIPTION_BUNDLE, bundleId, context);
-        }
-
-        // Update bac_tags
-        // TODO: refresh all tags
-        updateTags(account, context);
-    }
-
-    private Set<UUID> updateBST(final Account account, final InternalCallContext internalCallContext) {
-        // Find the current state of bundles in entitlement
-        final Collection<UUID> entitlementBundlesId = Collections2.transform(entitlementInternalApi.getBundlesForAccount(account.getId(), internalCallContext),
-                                                                             new Function<SubscriptionBundle, UUID>() {
-
-                                                                                 public UUID apply(@Nullable final SubscriptionBundle input) {
-                                                                                     if (input == null) {
-                                                                                         return null;
-                                                                                     } else {
-                                                                                         return input.getId();
-                                                                                     }
-                                                                                 }
-                                                                             });
-
-        // Find the current state of bundles in analytics
-        final Collection<UUID> analyticsBundlesId = Collections2.transform(analyticsDao.getTransitionsForAccount(account.getExternalKey(), internalCallContext),
-                                                                           new Function<BusinessSubscriptionTransitionModelDao, UUID>() {
-
-                                                                               public UUID apply(@Nullable final BusinessSubscriptionTransitionModelDao input) {
-                                                                                   if (input == null) {
-                                                                                       return null;
-                                                                                   } else {
-                                                                                       return input.getBundleId();
-                                                                                   }
-                                                                               }
-                                                                           });
-
-        // Update BST for all bundles found
-        final Set<UUID> bundlesId = new HashSet<UUID>();
-        bundlesId.addAll(entitlementBundlesId);
-        bundlesId.addAll(analyticsBundlesId);
-        for (final UUID bundleId : bundlesId) {
-            bstDao.update(bundleId, internalCallContext);
-        }
-
-        return bundlesId;
-    }
-
-    private void updateBIP(final Account account, final InternalCallContext internalCallContext) throws PaymentApiException {
-        final List<Payment> accountPayments = paymentApi.getAccountPayments(account.getId(), internalCallContext);
-        final Map<UUID, Payment> payments = new HashMap<UUID, Payment>();
-        for (final Payment payment : accountPayments) {
-            payments.put(payment.getId(), payment);
+            // Refresh tags
+            bTagDao.update(accountId, objectType, context);
         }
 
-        // Find the current state of payments in payment
-        final Collection<UUID> paymentPaymentsId = Collections2.transform(accountPayments,
-                                                                          new Function<Payment, UUID>() {
-
-                                                                              public UUID apply(@Nullable final Payment input) {
-                                                                                  if (input == null) {
-                                                                                      return null;
-                                                                                  } else {
-                                                                                      return input.getId();
-                                                                                  }
-                                                                              }
-                                                                          });
-
-        // Find the current state of payments in analytics
-        final Collection<UUID> analyticsPaymentsId = Collections2.transform(analyticsDao.getInvoicePaymentsForAccountByKey(account.getExternalKey(), internalCallContext),
-                                                                            new Function<BusinessInvoicePaymentModelDao, UUID>() {
-
-                                                                                public UUID apply(@Nullable final BusinessInvoicePaymentModelDao input) {
-                                                                                    if (input == null) {
-                                                                                        return null;
-                                                                                    } else {
-                                                                                        return input.getPaymentId();
-                                                                                    }
-                                                                                }
-                                                                            });
-
-        // Update BIP for all payments found
-        final Set<UUID> paymentsId = new HashSet<UUID>();
-        paymentsId.addAll(paymentPaymentsId);
-        paymentsId.addAll(analyticsPaymentsId);
-        for (final UUID paymentId : paymentsId) {
-            final Payment paymentInfo = payments.get(paymentId);
-            bipDao.invoicePaymentPosted(paymentInfo.getAccountId(),
-                                        paymentInfo.getId(),
-                                        paymentInfo.getPaymentStatus().toString(),
-                                        internalCallContext);
-        }
-    }
-
-    private void updateTags(final Account account, final InternalCallContext internalCallContext) {
-        // Find the current state of tags from util
-        final List<TagDefinition> tagDefinitions = tagInternalApi.getTagDefinitions(internalCallContext);
-        final Collection<String> utilTags = Collections2.transform(tagInternalApi.getTags(account.getId(), ObjectType.ACCOUNT, internalCallContext),
-                                                                   new Function<Tag, String>() {
-
-                                                                       public String apply(@Nullable final Tag input) {
-                                                                           if (input == null) {
-                                                                               return "";
-                                                                           }
-
-                                                                           for (final TagDefinition tagDefinition : tagDefinitions) {
-                                                                               if (tagDefinition.getId().equals(input.getTagDefinitionId())) {
-                                                                                   return tagDefinition.getName();
-                                                                               }
-                                                                           }
-                                                                           return "";
-                                                                       }
-                                                                   });
-
-        // Find the current state of tags in analytics
-        final Collection<String> analyticsTags = Collections2.transform(analyticsDao.getTagsForAccount(account.getExternalKey(), internalCallContext),
-                                                                        new Function<BusinessAccountTagModelDao, String>() {
-
-                                                                            public String apply(@Nullable final BusinessAccountTagModelDao input) {
-                                                                                if (input == null) {
-                                                                                    return null;
-                                                                                } else {
-                                                                                    return input.getName();
-                                                                                }
-                                                                            }
-                                                                        });
-
-        // Remove non existing tags
-        for (final String tag : Sets.difference(new HashSet<String>(analyticsTags), new HashSet<String>(utilTags))) {
-            tagDao.tagRemoved(ObjectType.ACCOUNT, account.getId(), tag, internalCallContext);
-        }
-
-        // Add missing ones
-        for (final String tag : Sets.difference(new HashSet<String>(utilTags), new HashSet<String>(analyticsTags))) {
-            tagDao.tagAdded(ObjectType.ACCOUNT, account.getId(), tag, internalCallContext);
-        }
+        logService.log(LogService.LOG_INFO, "Finished rebuild of Analytics for account " + accountId);
     }
 }
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/BusinessAnalyticsBase.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/BusinessAnalyticsBase.java
index f877953..3ff8968 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/BusinessAnalyticsBase.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/BusinessAnalyticsBase.java
@@ -335,7 +335,8 @@ public abstract class BusinessAnalyticsBase {
     protected Collection<CustomField> getFieldsForAccountAndObjectType(final UUID accountId, final ObjectType objectType, final TenantContext context) throws AnalyticsRefreshException {
         final CustomFieldUserApi tagUserApi = getCustomFieldUserApi();
         // TODO
-        return tagUserApi.getCustomFieldsForAccount(accountId, objectType, context);
+        //return tagUserApi.getCustomFieldsForAccount(accountId, objectType, context);
+        return null;
     }
 
     protected AuditLog getFieldCreationAuditLog(final UUID fieldId, final TenantContext context) throws AnalyticsRefreshException {
@@ -356,7 +357,8 @@ public abstract class BusinessAnalyticsBase {
     protected Collection<Tag> getTagsForAccountAndObjectType(final UUID accountId, final ObjectType objectType, final TenantContext context) throws AnalyticsRefreshException {
         final TagUserApi tagUserApi = getTagUserApi();
         // TODO
-        return tagUserApi.getTagsForAccount(accountId, objectType, context);
+        //return tagUserApi.getTagsForAccount(accountId, objectType, context);
+        return null;
     }
 
     protected TagDefinition getTagDefinition(final UUID tagDefinitionId, final TenantContext context) throws AnalyticsRefreshException {
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/AnalyticsDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/AnalyticsDao.java
index f5c8333..7137c3c 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/AnalyticsDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/AnalyticsDao.java
@@ -14,17 +14,27 @@
  * under the License.
  */
 
-package com.ning.billing.osgi.bundles.analytics.dao
+package com.ning.billing.osgi.bundles.analytics.dao;
 
+import java.util.Collection;
 import java.util.List;
+import java.util.UUID;
 
+import com.ning.billing.osgi.bundles.analytics.api.BusinessAccount;
+import com.ning.billing.osgi.bundles.analytics.api.BusinessField;
+import com.ning.billing.osgi.bundles.analytics.api.BusinessInvoice;
+import com.ning.billing.osgi.bundles.analytics.api.BusinessInvoicePayment;
+import com.ning.billing.osgi.bundles.analytics.api.BusinessOverdueStatus;
+import com.ning.billing.osgi.bundles.analytics.api.BusinessSubscriptionTransition;
+import com.ning.billing.osgi.bundles.analytics.api.BusinessTag;
 import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessAccountModelDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessAccountTagModelDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessFieldModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBaseModelDao;
 import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceModelDao;
-import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoicePaymentModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoicePaymentBaseModelDao;
 import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessOverdueStatusModelDao;
 import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessSubscriptionTransitionModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessTagModelDao;
 import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.killbill.osgi.libs.killbill.OSGIKillbillAPI;
 import com.ning.killbill.osgi.libs.killbill.OSGIKillbillDataSource;
@@ -38,21 +48,74 @@ public class AnalyticsDao extends BusinessAnalyticsDaoBase {
         super(logService, osgiKillbillAPI, osgiKillbillDataSource);
     }
 
-    public BusinessAccountModelDao getAccountByKey(final String accountExternalKey, final TenantContext context) {
+    public BusinessAccount getAccountById(final UUID accountId, final TenantContext context) {
+        final Long accountRecordId = getAccountRecordId(accountId);
+        final Long tenantRecordId = getTenantRecordId(context);
+
+        final BusinessAccountModelDao businessAccountModelDao = sqlDao.getAccountByAccountRecordId(accountRecordId, tenantRecordId, context);
+        if (businessAccountModelDao == null) {
+            return null;
+        } else {
+            return new BusinessAccount(businessAccountModelDao);
+        }
+    }
+
+    public Collection<BusinessSubscriptionTransition> getSubscriptionTransitionsForAccount(final UUID accountId, final TenantContext context) {
+        final Long accountRecordId = getAccountRecordId(accountId);
+        final Long tenantRecordId = getTenantRecordId(context);
+
+        final List<BusinessSubscriptionTransitionModelDao> businessSubscriptionTransitionModelDaos = sqlDao.getSubscriptionTransitionsByAccountRecordId(accountRecordId, tenantRecordId, context);
+        return null;
     }
 
-    public List<BusinessSubscriptionTransitionModelDao> getSubscriptionTransitionsByBundleExternalKey(final String bundleExternalKey, final TenantContext context) {
+    public Collection<BusinessOverdueStatus> getOverdueStatusesForAccount(final UUID accountId, final TenantContext context) {
+        final Long accountRecordId = getAccountRecordId(accountId);
+        final Long tenantRecordId = getTenantRecordId(context);
+
+        final List<BusinessOverdueStatusModelDao> businessOverdueStatusModelDaos = sqlDao.getOverdueStatusesByAccountRecordId(accountRecordId, tenantRecordId, context);
+        return null;
     }
 
-    public List<BusinessSubscriptionTransitionModelDao> getTransitionsForAccount(String accountKey, TenantContext context) {}
+    public Collection<BusinessInvoice> getInvoicesForAccount(final UUID accountId, final TenantContext context) {
+        final Long accountRecordId = getAccountRecordId(accountId);
+        final Long tenantRecordId = getTenantRecordId(context);
 
-    public List<BusinessInvoiceModelDao> getInvoicesByAccountKey(String accountExternalKey, TenantContext context) {}
+        final List<BusinessInvoiceModelDao> businessInvoiceModelDaos = sqlDao.getInvoicesByAccountRecordId(accountRecordId, tenantRecordId, context);
+        final List<BusinessInvoiceItemBaseModelDao> businessInvoiceItemModelDaos = sqlDao.getInvoiceItemsByAccountRecordId(accountRecordId, tenantRecordId, context);
+        return null;
+    }
 
-    public List<BusinessInvoiceItemModelDao> getInvoiceItemsForAccountKey(String accountExternalKey, TenantContext context) {}
+    public Collection<BusinessInvoicePayment> getInvoicePaymentsForAccount(final UUID accountId, final TenantContext context) {
+        final Long accountRecordId = getAccountRecordId(accountId);
+        final Long tenantRecordId = getTenantRecordId(context);
 
-    public List<BusinessInvoicePaymentModelDao> getInvoicePaymentsForAccountByKey(String accountExternalKey, TenantContext context) {}
+        final List<BusinessInvoicePaymentBaseModelDao> businessInvoicePaymentBaseModelDaos = sqlDao.getInvoicePaymentsByAccountRecordId(accountRecordId, tenantRecordId, context);
+        return null;
+    }
 
-    public List<BusinessOverdueStatusModelDao> getOverdueStatusesForBundleByExternalKey(String bundleExternalKey, TenantContext context) {}
+    public Collection<BusinessField> getFieldsForAccount(final UUID accountId, final TenantContext context) {
+        final Long accountRecordId = getAccountRecordId(accountId);
+        final Long tenantRecordId = getTenantRecordId(context);
 
-    public List<BusinessAccountTagModelDao> getTagsForAccount(String accountKey, TenantContext context) {}
+        final List<BusinessFieldModelDao> businessFieldModelDaos = sqlDao.getFieldsByAccountRecordId(accountRecordId, tenantRecordId, context);
+        return null;
+    }
+
+    public Collection<BusinessTag> getTagsForAccount(final UUID accountId, final TenantContext context) {
+        final Long accountRecordId = getAccountRecordId(accountId);
+        final Long tenantRecordId = getTenantRecordId(context);
+
+        final List<BusinessTagModelDao> businessTagModelDaos = sqlDao.getTagsByAccountRecordId(accountRecordId, tenantRecordId, context);
+        return null;
+    }
+
+    private Long getAccountRecordId(final UUID accountId) {
+        // TODO
+        return 0L;
+    }
+
+    private Long getTenantRecordId(final TenantContext context) {
+        // TODO
+        return 0L;
+    }
 }
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.java
index ed577e3..8fcb937 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.osgi.bundles.analytics.dao;
 
+import java.util.List;
+
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.BindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
@@ -23,7 +25,15 @@ import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator;
 
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessAccountModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessFieldModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBaseModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoicePaymentBaseModelDao;
 import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessModelDaoBase;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessOverdueStatusModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessSubscriptionTransitionModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessTagModelDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.TenantContext;
 
@@ -42,7 +52,42 @@ public interface BusinessAnalyticsSqlDao extends Transactional<BusinessAnalytics
                                         @BindBean final CallContext callContext);
 
     @SqlQuery
-    public Iterable findByAccountRecordId(@Bind("tableName") final String tableName,
-                                          @Bind("accountRecordId") final Long accountRecordId,
-                                          @BindBean final TenantContext callContext);
+    public BusinessAccountModelDao getAccountByAccountRecordId(@Bind("accountRecordId") final Long accountRecordId,
+                                                               @Bind("tenantRecordId") final Long tenantRecordId,
+                                                               @BindBean final TenantContext tenantContext);
+
+    @SqlQuery
+    public List<BusinessSubscriptionTransitionModelDao> getSubscriptionTransitionsByAccountRecordId(@Bind("accountRecordId") final Long accountRecordId,
+                                                                                                    @Bind("tenantRecordId") final Long tenantRecordId,
+                                                                                                    @BindBean final TenantContext tenantContext);
+
+    @SqlQuery
+    public List<BusinessOverdueStatusModelDao> getOverdueStatusesByAccountRecordId(@Bind("accountRecordId") final Long accountRecordId,
+                                                                                   @Bind("tenantRecordId") final Long tenantRecordId,
+                                                                                   @BindBean final TenantContext tenantContext);
+
+    @SqlQuery
+    public List<BusinessInvoiceModelDao> getInvoicesByAccountRecordId(@Bind("accountRecordId") final Long accountRecordId,
+                                                                      @Bind("tenantRecordId") final Long tenantRecordId,
+                                                                      @BindBean final TenantContext tenantContext);
+
+    @SqlQuery
+    public List<BusinessInvoiceItemBaseModelDao> getInvoiceItemsByAccountRecordId(@Bind("accountRecordId") final Long accountRecordId,
+                                                                                  @Bind("tenantRecordId") final Long tenantRecordId,
+                                                                                  @BindBean final TenantContext tenantContext);
+
+    @SqlQuery
+    public List<BusinessInvoicePaymentBaseModelDao> getInvoicePaymentsByAccountRecordId(@Bind("accountRecordId") final Long accountRecordId,
+                                                                                        @Bind("tenantRecordId") final Long tenantRecordId,
+                                                                                        @BindBean final TenantContext tenantContext);
+
+    @SqlQuery
+    public List<BusinessFieldModelDao> getFieldsByAccountRecordId(@Bind("accountRecordId") final Long accountRecordId,
+                                                                  @Bind("tenantRecordId") final Long tenantRecordId,
+                                                                  @BindBean final TenantContext tenantContext);
+
+    @SqlQuery
+    public List<BusinessTagModelDao> getTagsByAccountRecordId(@Bind("accountRecordId") final Long accountRecordId,
+                                                              @Bind("tenantRecordId") final Long tenantRecordId,
+                                                              @BindBean final TenantContext tenantContext);
 }
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessOverdueStatusDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessOverdueStatusDao.java
index 0d22ae8..f3dd1c9 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessOverdueStatusDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessOverdueStatusDao.java
@@ -49,20 +49,23 @@ public class BusinessOverdueStatusDao extends BusinessAnalyticsDaoBase {
         super(logService, osgiKillbillAPI, osgiKillbillDataSource);
     }
 
-    public void update(final ObjectType objectType, final UUID objectId, final CallContext context) throws AnalyticsRefreshException {
+    public void update(final UUID accountId, final ObjectType objectType, final CallContext context) throws AnalyticsRefreshException {
         if (ObjectType.BUNDLE.equals(objectType)) {
-            updateForBundle(objectId, context);
+            updateForBundle(accountId, context);
         } else {
-            logService.log(LogService.LOG_WARNING, String.format("Ignoring overdue status change for object id %s (type %s)", objectId.toString(), objectType.toString()));
+            logService.log(LogService.LOG_WARNING, String.format("Ignoring overdue status change for account id %s (type %s)", accountId, objectType.toString()));
         }
     }
 
-    private void updateForBundle(final UUID bundleId, final CallContext context) throws AnalyticsRefreshException {
-        final SubscriptionBundle bundle = getSubscriptionBundle(bundleId, context);
-        final Account account = getAccount(bundle.getAccountId(), context);
+    private void updateForBundle(final UUID accountId, final CallContext context) throws AnalyticsRefreshException {
+        final Account account = getAccount(accountId, context);
 
-        // Recompute all blocking states for that bundle
-        final Collection<BusinessOverdueStatusModelDao> businessOverdueStatuses = createBusinessOverdueStatuses(account, bundle, context);
+        final Collection<SubscriptionBundle> bundles = getSubscriptionBundlesForAccount(accountId, context);
+        final Collection<BusinessOverdueStatusModelDao> businessOverdueStatuses = new LinkedList<BusinessOverdueStatusModelDao>();
+        for (final SubscriptionBundle bundle : bundles) {
+            // Recompute all blocking states for that bundle
+            businessOverdueStatuses.addAll(createBusinessOverdueStatuses(account, bundle, context));
+        }
 
         sqlDao.inTransaction(new Transaction<Void, BusinessAnalyticsSqlDao>() {
             @Override