diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index b4fc7de..265a1fa 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project 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
@@ -443,52 +443,70 @@ public class AccountResource extends JaxRsResourceBase {
final Future<List<InvoicePayment>> futureInvoicePaymentsCallable = executor.submit(invoicePaymentsCallable);
final Future<List<Payment>> futurePaymentsCallable = executor.submit(paymentsCallable);
final Future<AccountAuditLogs> futureAuditsCallable = executor.submit(auditsCallable);
-
- try {
- final long ini = System.currentTimeMillis();
- do {
- bundles = (bundles == null) ? runCallableAndHandleTimeout(futureBundlesCallable, 100) : bundles;
- invoices = (invoices == null) ? runCallableAndHandleTimeout(futureInvoicesCallable, 100) : invoices;
- invoicePayments = (invoicePayments == null) ? runCallableAndHandleTimeout(futureInvoicePaymentsCallable, 100) : invoicePayments;
- payments = (payments == null) ? runCallableAndHandleTimeout(futurePaymentsCallable, 100) : payments;
- accountAuditLogs = (accountAuditLogs == null) ? runCallableAndHandleTimeout(futureAuditsCallable, 100) : accountAuditLogs;
- } while ((System.currentTimeMillis() - ini < jaxrsConfig.getJaxrsTimeout().getMillis()) &&
- (bundles == null || invoices == null || invoicePayments == null || payments == null || accountAuditLogs == null));
-
- if (bundles == null || invoices == null || invoicePayments == null || payments == null || accountAuditLogs == null) {
- Response.status(Status.SERVICE_UNAVAILABLE).build();
- }
- } catch (final InterruptedException e) {
- handleCallableException(e, ImmutableList.<Future>of(futureBundlesCallable, futureInvoicesCallable, futureInvoicePaymentsCallable, futurePaymentsCallable, futureAuditsCallable));
- } catch (final ExecutionException e) {
- handleCallableException(e.getCause(), ImmutableList.<Future>of(futureBundlesCallable, futureInvoicesCallable, futureInvoicePaymentsCallable, futurePaymentsCallable, futureAuditsCallable));
+ final ImmutableList<Future> toBeCancelled = ImmutableList.<Future>of(futureBundlesCallable, futureInvoicesCallable, futureInvoicePaymentsCallable, futurePaymentsCallable, futureAuditsCallable);
+ final int timeoutMsec = 100;
+
+ final long ini = System.currentTimeMillis();
+ do {
+ bundles = (bundles == null) ? waitOnFutureAndHandleTimeout("bundles", futureBundlesCallable, timeoutMsec, toBeCancelled) : bundles;
+ invoices = (invoices == null) ? waitOnFutureAndHandleTimeout("invoices", futureInvoicesCallable, timeoutMsec, toBeCancelled) : invoices;
+ invoicePayments = (invoicePayments == null) ? waitOnFutureAndHandleTimeout("invoicePayments", futureInvoicePaymentsCallable, timeoutMsec, toBeCancelled) : invoicePayments;
+ payments = (payments == null) ? waitOnFutureAndHandleTimeout("payments", futurePaymentsCallable, timeoutMsec, toBeCancelled) : payments;
+ accountAuditLogs = (accountAuditLogs == null) ? waitOnFutureAndHandleTimeout("accountAuditLogs", futureAuditsCallable, timeoutMsec, toBeCancelled) : accountAuditLogs;
+ } while ((System.currentTimeMillis() - ini < jaxrsConfig.getJaxrsTimeout().getMillis()) &&
+ (bundles == null || invoices == null || invoicePayments == null || payments == null || accountAuditLogs == null));
+
+ if (bundles == null || invoices == null || invoicePayments == null || payments == null || accountAuditLogs == null) {
+ Response.status(Status.SERVICE_UNAVAILABLE).build();
}
-
} else {
- try {
- invoices = invoicesCallable.call();
- payments = paymentsCallable.call();
- bundles = bundlesCallable.call();
- accountAuditLogs = auditsCallable.call();
- invoicePayments = invoicePaymentsCallable.call();
- } catch (final Exception e) {
- handleCallableException(e);
- }
+ invoices = runCallable("invoices", invoicesCallable);
+ payments = runCallable("payments", paymentsCallable);
+ bundles = runCallable("bundles", bundlesCallable);
+ accountAuditLogs = runCallable("accountAuditLogs", auditsCallable);
+ invoicePayments = runCallable("invoicePayments", invoicePaymentsCallable);
}
json = new AccountTimelineJson(account, invoices, payments, invoicePayments, bundles, accountAuditLogs);
return Response.status(Status.OK).entity(json).build();
}
- private <T> T runCallableAndHandleTimeout(final Future<T> future, final long timeoutMsec) throws ExecutionException, InterruptedException {
+ private <T> T waitOnFutureAndHandleTimeout(final String logSuffix, final Future<T> future, final long timeoutMsec, final Iterable<Future> toBeCancelled) throws PaymentApiException, AccountApiException, InvoiceApiException, SubscriptionApiException {
+ try {
+ return waitOnFutureAndHandleTimeout(future, timeoutMsec);
+ } catch (final InterruptedException e) {
+ log.warn("InterruptedException while retrieving {}", logSuffix, e);
+ handleCallableException(e, toBeCancelled);
+ } catch (final ExecutionException e) {
+ log.warn("ExecutionException while retrieving {}", logSuffix, e);
+ handleCallableException(e.getCause(), toBeCancelled);
+ }
+
+ // Never reached
+ return null;
+ }
+
+ private <T> T waitOnFutureAndHandleTimeout(final Future<T> future, final long timeoutMsec) throws ExecutionException, InterruptedException {
try {
return future.get(timeoutMsec, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
+ } catch (final TimeoutException e) {
return null;
}
}
- private void handleCallableException(final Throwable causeOrException, final List<Future> toBeCancelled) throws AccountApiException, SubscriptionApiException, PaymentApiException, InvoiceApiException {
+ private <T> T runCallable(final String logSuffix, final Callable<T> callable) throws PaymentApiException, AccountApiException, InvoiceApiException, SubscriptionApiException {
+ try {
+ return callable.call();
+ } catch (final Exception e) {
+ log.warn("InterruptedException while retrieving {}", logSuffix, e);
+ handleCallableException(e);
+ }
+
+ // Never reached
+ return null;
+ }
+
+ private void handleCallableException(final Throwable causeOrException, final Iterable<Future> toBeCancelled) throws AccountApiException, SubscriptionApiException, PaymentApiException, InvoiceApiException {
for (final Future f : toBeCancelled) {
f.cancel(true);
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
index 66eb996..b0a42f3 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project 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
@@ -26,6 +26,8 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
+import org.killbill.billing.client.KillBillClientException;
+import org.killbill.billing.client.RequestOptions;
import org.killbill.billing.client.model.Account;
import org.killbill.billing.client.model.AccountTimeline;
import org.killbill.billing.client.model.AuditLog;
@@ -42,6 +44,10 @@ import org.killbill.billing.util.audit.ChangeType;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.collect.HashMultimap;
+
+import static org.killbill.billing.jaxrs.resources.JaxrsResource.QUERY_PARALLEL;
+
public class TestAccountTimeline extends TestJaxrsBase {
private static final String PAYMENT_REQUEST_PROCESSOR = "PaymentRequestProcessor";
@@ -53,7 +59,7 @@ public class TestAccountTimeline extends TestJaxrsBase {
final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
- final AccountTimeline timeline = killBillClient.getAccountTimeline(accountJson.getAccountId());
+ final AccountTimeline timeline = getAccountTimeline(accountJson.getAccountId(), AuditLevel.NONE);
Assert.assertEquals(timeline.getPayments().size(), 1);
Assert.assertEquals(timeline.getInvoices().size(), 2);
Assert.assertEquals(timeline.getBundles().size(), 1);
@@ -113,7 +119,7 @@ public class TestAccountTimeline extends TestJaxrsBase {
private void verifyPayments(final UUID accountId, final DateTime startTime, final DateTime endTime,
final BigDecimal refundAmount, final BigDecimal chargebackAmount) throws Exception {
for (final AuditLevel auditLevel : AuditLevel.values()) {
- final AccountTimeline timeline = killBillClient.getAccountTimeline(accountId, auditLevel);
+ final AccountTimeline timeline = getAccountTimeline(accountId, auditLevel);
Assert.assertEquals(timeline.getPayments().size(), 1);
final InvoicePayment payment = timeline.getPayments().get(0);
@@ -183,7 +189,7 @@ public class TestAccountTimeline extends TestJaxrsBase {
private void verifyInvoices(final UUID accountId, final DateTime startTime, final DateTime endTime) throws Exception {
for (final AuditLevel auditLevel : AuditLevel.values()) {
- final AccountTimeline timeline = killBillClient.getAccountTimeline(accountId, auditLevel);
+ final AccountTimeline timeline = getAccountTimeline(accountId, auditLevel);
// Verify invoices
Assert.assertEquals(timeline.getInvoices().size(), 3);
@@ -209,7 +215,7 @@ public class TestAccountTimeline extends TestJaxrsBase {
private void verifyCredits(final UUID accountId, final DateTime startTime, final DateTime endTime, final BigDecimal creditAmount) throws Exception {
for (final AuditLevel auditLevel : AuditLevel.values()) {
- final AccountTimeline timeline = killBillClient.getAccountTimeline(accountId, auditLevel);
+ final AccountTimeline timeline = getAccountTimeline(accountId, auditLevel);
// Verify credits
final List<Credit> credits = timeline.getInvoices().get(1).getCredits();
@@ -229,7 +235,7 @@ public class TestAccountTimeline extends TestJaxrsBase {
private void verifyBundles(final UUID accountId, final DateTime startTime, final DateTime endTime) throws Exception {
for (final AuditLevel auditLevel : AuditLevel.values()) {
- final AccountTimeline timeline = killBillClient.getAccountTimeline(accountId, auditLevel);
+ final AccountTimeline timeline = getAccountTimeline(accountId, auditLevel);
// Verify bundles
Assert.assertEquals(timeline.getBundles().size(), 1);
@@ -298,4 +304,17 @@ public class TestAccountTimeline extends TestJaxrsBase {
Assert.assertEquals(auditLogJson.getComments(), comments);
Assert.assertEquals(auditLogJson.getChangedBy(), changedBy);
}
+
+ private AccountTimeline getAccountTimeline(final UUID accountId, final AuditLevel auditLevel) throws KillBillClientException {
+ final AccountTimeline accountTimeline = killBillClient.getAccountTimeline(accountId, auditLevel, RequestOptions.empty());
+
+ // Verify also the parallel path
+ final HashMultimap<String, String> queryParams = HashMultimap.<String, String>create();
+ queryParams.put(QUERY_PARALLEL, "true");
+ final RequestOptions requestOptions = RequestOptions.builder().withQueryParams(queryParams).build();
+ final AccountTimeline accountTimelineInParallel = killBillClient.getAccountTimeline(accountId, auditLevel, requestOptions);
+ Assert.assertEquals(accountTimelineInParallel, accountTimeline);
+
+ return accountTimeline;
+ }
}