killbill-aplcache
Changes
analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java 216(+214 -2)
analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java 4(+4 -0)
analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg 42(+42 -0)
analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java 21(+20 -1)
Details
diff --git a/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java b/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
index fb74122..840f483 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
@@ -16,11 +16,27 @@
package com.ning.billing.analytics.api.user;
+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 javax.inject.Inject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.analytics.BusinessAccountDao;
+import com.ning.billing.analytics.BusinessInvoiceDao;
+import com.ning.billing.analytics.BusinessInvoicePaymentDao;
+import com.ning.billing.analytics.BusinessOverdueStatusDao;
+import com.ning.billing.analytics.BusinessSubscriptionTransitionDao;
+import com.ning.billing.analytics.BusinessTagDao;
import com.ning.billing.analytics.api.TimeSeriesData;
import com.ning.billing.analytics.dao.AnalyticsDao;
import com.ning.billing.analytics.model.BusinessAccount;
@@ -30,17 +46,61 @@ import com.ning.billing.analytics.model.BusinessInvoiceItem;
import com.ning.billing.analytics.model.BusinessInvoicePayment;
import com.ning.billing.analytics.model.BusinessOverdueStatus;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.junction.api.Blockable.Type;
+import com.ning.billing.payment.api.Payment;
+import com.ning.billing.payment.api.PaymentApi;
+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.TenantContext;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
+import com.ning.billing.util.svcapi.tag.TagInternalApi;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
public class DefaultAnalyticsUserApi implements AnalyticsUserApi {
- private final InternalCallContextFactory internalCallContextFactory;
+ private static final Logger log = LoggerFactory.getLogger(DefaultAnalyticsUserApi.class);
+
private final AnalyticsDao analyticsDao;
+ private final BusinessSubscriptionTransitionDao bstDao;
+ private final BusinessAccountDao bacDao;
+ private final BusinessInvoiceDao invoiceDao;
+ private final BusinessOverdueStatusDao bosDao;
+ private final BusinessInvoicePaymentDao bipDao;
+ private final BusinessTagDao tagDao;
+ private final EntitlementInternalApi entitlementInternalApi;
+ private final PaymentApi paymentApi;
+ private final TagInternalApi tagInternalApi;
+ private final InternalCallContextFactory internalCallContextFactory;
@Inject
- public DefaultAnalyticsUserApi(final AnalyticsDao analyticsDao, final InternalCallContextFactory internalCallContextFactory) {
+ public DefaultAnalyticsUserApi(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 PaymentApi paymentApi,
+ final TagInternalApi tagInternalApi,
+ final InternalCallContextFactory internalCallContextFactory) {
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;
}
@@ -54,6 +114,158 @@ public class DefaultAnalyticsUserApi implements AnalyticsUserApi {
return analyticsDao.getSubscriptionsCreatedOverTime(productType, slug, internalCallContextFactory.createInternalTenantContext(context));
}
+ @Override
+ public void rebuildAnalyticsForAccount(final Account account, final CallContext context) {
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(context);
+
+ // Update the BAC row
+ bacDao.accountUpdated(account.getId(), internalCallContext);
+
+ // Update BST for all bundles
+ final Set<UUID> bundleIds = updateBST(account, internalCallContext);
+
+ // Update BIN and BII for all invoices
+ invoiceDao.rebuildInvoicesForAccount(account.getId(), internalCallContext);
+
+ // Update BIP for all invoices
+ try {
+ updateBIP(account, context, internalCallContext);
+ } 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, internalCallContext);
+ }
+
+ // Update bac_tags
+ // TODO: refresh all tags
+ updateTags(account, internalCallContext);
+ }
+
+ 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>() {
+ @Override
+ 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<BusinessSubscriptionTransition, UUID>() {
+ @Override
+ public UUID apply(@Nullable final BusinessSubscriptionTransition 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.rebuildTransitionsForBundle(bundleId, internalCallContext);
+ }
+
+ return bundlesId;
+ }
+
+ private void updateBIP(final Account account, final TenantContext tenantContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final List<Payment> accountPayments = paymentApi.getAccountPayments(account.getId(), tenantContext);
+ final Map<UUID, Payment> payments = new HashMap<UUID, Payment>();
+ for (final Payment payment : accountPayments) {
+ payments.put(payment.getId(), payment);
+ }
+
+ // Find the current state of payments in payment
+ final Collection<UUID> paymentPaymentsId = Collections2.transform(accountPayments,
+ new Function<Payment, UUID>() {
+ @Override
+ 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<BusinessInvoicePayment, UUID>() {
+ @Override
+ public UUID apply(@Nullable final BusinessInvoicePayment 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.getExtFirstPaymentIdRef(),
+ paymentInfo.getExtSecondPaymentIdRef(),
+ paymentInfo.getPaymentStatus().toString(),
+ internalCallContext);
+ }
+ }
+
+ private void updateTags(final Account account, final InternalCallContext internalCallContext) {
+ // Find the current state of tags from util
+ final Collection<String> utilTags = Collections2.transform(tagInternalApi.getTags(account.getId(), ObjectType.ACCOUNT, internalCallContext).keySet(),
+ new Function<String, String>() {
+ @Override
+ public String apply(@Nullable final String input) {
+ return input;
+ }
+ });
+
+ // Find the current state of tags in analytics
+ final Collection<String> analyticsTags = Collections2.transform(analyticsDao.getTagsForAccount(account.getExternalKey(), internalCallContext),
+ new Function<BusinessAccountTag, String>() {
+ @Override
+ public String apply(@Nullable final BusinessAccountTag 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);
+ }
+ }
+
// Note: the following is not exposed in api yet, as the models need to be extracted first
public BusinessAccount getAccountByKey(final String accountKey, final TenantContext context) {
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
index d99f5b8..7c4ab6c 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
@@ -38,6 +38,8 @@ public interface AnalyticsDao {
List<BusinessSubscriptionTransition> getTransitionsByKey(String externalKey, InternalTenantContext context);
+ List<BusinessSubscriptionTransition> getTransitionsForAccount(String accountKey, InternalTenantContext context);
+
List<BusinessInvoice> getInvoicesByKey(String accountKey, InternalTenantContext context);
List<BusinessAccountTag> getTagsForAccount(String accountKey, InternalTenantContext context);
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
index 6706537..0e65c7b 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
@@ -47,6 +47,10 @@ public interface BusinessSubscriptionTransitionSqlDao extends Transactional<Busi
List<BusinessSubscriptionTransition> getTransitionForSubscription(@Bind("subscription_id") final String subscriptionId,
@InternalTenantContextBinder final InternalTenantContext context);
+ @SqlQuery
+ List<BusinessSubscriptionTransition> getTransitionsForAccount(@Bind("account_key") final String accountKey,
+ @InternalTenantContextBinder final InternalTenantContext context);
+
@SqlUpdate
int createTransition(@BusinessSubscriptionTransitionBinder final BusinessSubscriptionTransition transition,
@InternalTenantContextBinder final InternalCallContext context);
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
index 59e9af8..e91c988 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
@@ -79,6 +79,11 @@ public class DefaultAnalyticsDao implements AnalyticsDao {
}
@Override
+ public List<BusinessSubscriptionTransition> getTransitionsForAccount(final String accountKey, final InternalTenantContext context) {
+ return subscriptionTransitionSqlDao.getTransitionsForAccount(accountKey, context);
+ }
+
+ @Override
public List<BusinessInvoice> getInvoicesByKey(final String accountKey, final InternalTenantContext context) {
return invoiceSqlDao.getInvoicesForAccountByKey(accountKey, context);
}
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
index 8649840..8f85dd6 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
+++ b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
@@ -101,6 +101,48 @@ getTransitionForSubscription(subscription_id) ::= <<
;
>>
+getTransitionsForAccount(account_id) ::= <<
+ select
+ total_ordering
+ , bundle_id
+ , external_key
+ , account_id
+ , account_key
+ , subscription_id
+ , requested_timestamp
+ , event
+ , prev_product_name
+ , prev_product_type
+ , prev_product_category
+ , prev_slug
+ , prev_phase
+ , prev_billing_period
+ , prev_price
+ , prev_price_list
+ , prev_mrr
+ , prev_currency
+ , prev_start_date
+ , prev_state
+ , next_product_name
+ , next_product_type
+ , next_product_category
+ , next_slug
+ , next_phase
+ , next_billing_period
+ , next_price
+ , next_price_list
+ , next_mrr
+ , next_currency
+ , next_start_date
+ , next_state
+ , tenant_record_id
+ from bst
+ where account_key = :account_key
+ <AND_CHECK_TENANT()>
+ order by requested_timestamp asc
+ ;
+>>
+
createTransition() ::= <<
insert into bst(
total_ordering
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
index 70cb427..905aa2a 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
@@ -27,6 +27,12 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.ning.billing.analytics.AnalyticsTestSuiteWithEmbeddedDB;
+import com.ning.billing.analytics.BusinessAccountDao;
+import com.ning.billing.analytics.BusinessInvoiceDao;
+import com.ning.billing.analytics.BusinessInvoicePaymentDao;
+import com.ning.billing.analytics.BusinessOverdueStatusDao;
+import com.ning.billing.analytics.BusinessSubscriptionTransitionDao;
+import com.ning.billing.analytics.BusinessTagDao;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
import com.ning.billing.analytics.MockProduct;
@@ -53,10 +59,13 @@ import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.mock.MockPlan;
+import com.ning.billing.payment.api.PaymentApi;
import com.ning.billing.util.callcontext.InternalCallContextFactory;
import com.ning.billing.util.callcontext.TenantContext;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
+import com.ning.billing.util.svcapi.tag.TagInternalApi;
public class TestDefaultAnalyticsUserApi extends AnalyticsTestSuiteWithEmbeddedDB {
@@ -85,7 +94,17 @@ public class TestDefaultAnalyticsUserApi extends AnalyticsTestSuiteWithEmbeddedD
final AnalyticsDao analyticsDao = new DefaultAnalyticsDao(accountSqlDao, subscriptionTransitionSqlDao, invoiceSqlDao,
invoiceItemSqlDao, accountTagSqlDao, overdueStatusSqlDao, invoicePaymentSqlDao);
- analyticsUserApi = new DefaultAnalyticsUserApi(analyticsDao, new InternalCallContextFactory(dbi, clock));
+ analyticsUserApi = new DefaultAnalyticsUserApi(analyticsDao,
+ Mockito.mock(BusinessSubscriptionTransitionDao.class),
+ Mockito.mock(BusinessAccountDao.class),
+ Mockito.mock(BusinessInvoiceDao.class),
+ Mockito.mock(BusinessOverdueStatusDao.class),
+ Mockito.mock(BusinessInvoicePaymentDao.class),
+ Mockito.mock(BusinessTagDao.class),
+ Mockito.mock(EntitlementInternalApi.class),
+ Mockito.mock(PaymentApi.class),
+ Mockito.mock(TagInternalApi.class),
+ new InternalCallContextFactory(dbi, clock));
}
@Test(groups = "slow")
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java b/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
index 58d3148..1cc7c31 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
@@ -60,6 +60,11 @@ public class MockBusinessSubscriptionTransitionSqlDao implements BusinessSubscri
}
@Override
+ public List<BusinessSubscriptionTransition> getTransitionsForAccount(@Bind("account_id") final String accountId, @InternalTenantContextBinder final InternalTenantContext context) {
+ return ImmutableList.<BusinessSubscriptionTransition>of();
+ }
+
+ @Override
public int createTransition(@BusinessSubscriptionTransitionBinder final BusinessSubscriptionTransition transition,
@InternalTenantContextBinder final InternalCallContext context) {
if (content.get(transition.getExternalKey()) == null) {
diff --git a/api/src/main/java/com/ning/billing/analytics/api/user/AnalyticsUserApi.java b/api/src/main/java/com/ning/billing/analytics/api/user/AnalyticsUserApi.java
index cbdea9b..ba5ae0f 100644
--- a/api/src/main/java/com/ning/billing/analytics/api/user/AnalyticsUserApi.java
+++ b/api/src/main/java/com/ning/billing/analytics/api/user/AnalyticsUserApi.java
@@ -16,7 +16,9 @@
package com.ning.billing.analytics.api.user;
+import com.ning.billing.account.api.Account;
import com.ning.billing.analytics.api.TimeSeriesData;
+import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.TenantContext;
public interface AnalyticsUserApi {
@@ -32,4 +34,12 @@ public interface AnalyticsUserApi {
* @return the number of new subscriptions created per day (transfers not included)
*/
public TimeSeriesData getSubscriptionsCreatedOverTime(String productType, String slug, TenantContext context);
+
+ /**
+ * Rebuild all analytics tables for an account
+ *
+ * @param account account
+ * @param context call context
+ */
+ void rebuildAnalyticsForAccount(Account account, CallContext context);
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AnalyticsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AnalyticsResource.java
index e8c871e..bbf996f 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AnalyticsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AnalyticsResource.java
@@ -16,15 +16,23 @@
package com.ning.billing.jaxrs.resources;
+import java.util.UUID;
+
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.analytics.api.TimeSeriesData;
import com.ning.billing.analytics.api.user.AnalyticsUserApi;
import com.ning.billing.jaxrs.json.TimeSeriesDataJson;
@@ -33,6 +41,7 @@ import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
import com.ning.billing.util.api.AuditUserApi;
import com.ning.billing.util.api.CustomFieldUserApi;
import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.callcontext.CallContext;
import com.google.inject.Singleton;
@@ -42,19 +51,35 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
@Path(JaxrsResource.ANALYTICS_PATH)
public class AnalyticsResource extends JaxRsResourceBase {
+ private final AccountUserApi accountUserApi;
private final AnalyticsUserApi analyticsUserApi;
@Inject
- public AnalyticsResource(final AnalyticsUserApi analyticsUserApi,
+ public AnalyticsResource(final AccountUserApi accountUserApi,
+ final AnalyticsUserApi analyticsUserApi,
final JaxrsUriBuilder uriBuilder,
final TagUserApi tagUserApi,
final CustomFieldUserApi customFieldUserApi,
final AuditUserApi auditUserApi,
final Context context) {
super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, context);
+ this.accountUserApi = accountUserApi;
this.analyticsUserApi = analyticsUserApi;
}
+ @PUT
+ @Path("/{accountId:" + UUID_PATTERN + "}")
+ public Response rebuildAnalyticsForAccount(@PathParam("accountId") final String accountId,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment,
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
+ final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+ final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);
+ analyticsUserApi.rebuildAnalyticsForAccount(account, callContext);
+ return Response.status(Status.OK).build();
+ }
+
@GET
@Path("/accountsCreatedOverTime")
@Produces(APPLICATION_JSON)