killbill-uncached

invoice: speedup invoiceDaoHelper.populateChildren Fetch

12/21/2013 3:45:06 PM

Details

diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDaoHelper.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDaoHelper.java
index 54965fd..801eaf7 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDaoHelper.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDaoHelper.java
@@ -19,6 +19,8 @@ package com.ning.billing.invoice.dao;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -40,11 +42,11 @@ import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap.Builder;
 
 public class InvoiceDaoHelper {
 
-
     /**
      * Find amounts to adjust for individual items, if not specified.
      * The user gives us a list of items to adjust associated with a given amount (how much to refund per invoice item).
@@ -57,7 +59,6 @@ public class InvoiceDaoHelper {
      * @param context                       the tenant callcontext
      * @return the final mapping between invoice item ids and amount to refund
      * @throws com.ning.billing.invoice.api.InvoiceApiException
-     *
      */
     public Map<UUID, BigDecimal> computeItemAdjustments(final String invoiceId,
                                                         final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory,
@@ -98,12 +99,10 @@ public class InvoiceDaoHelper {
         return invoiceItemIdsWithAmountsBuilder.build();
     }
 
-
     /**
-     * @param invoiceItem  item we are adjusting
-     * @param requestedPositiveAmountToAdjust
-     *                     amount we are adjusting for that item
-     * @param invoiceItems list of all invoice items on this invoice
+     * @param invoiceItem                     item we are adjusting
+     * @param requestedPositiveAmountToAdjust amount we are adjusting for that item
+     * @param invoiceItems                    list of all invoice items on this invoice
      * @return the amount we should really adjust based on whether or not the item got repaired
      */
     private BigDecimal computeItemAdjustmentAmount(final UUID invoiceItem, final BigDecimal requestedPositiveAmountToAdjust, final List<InvoiceItemModelDao> invoiceItems) {
@@ -155,13 +154,11 @@ public class InvoiceDaoHelper {
         return requestedPositiveAmount;
     }
 
-
     public List<InvoiceModelDao> getUnpaidInvoicesByAccountFromTransaction(final UUID accountId, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final LocalDate upToDate, final InternalTenantContext context) {
         final List<InvoiceModelDao> invoices = getAllInvoicesByAccountFromTransaction(entitySqlDaoWrapperFactory, context);
         return getUnpaidInvoicesByAccountFromTransaction(invoices, upToDate);
     }
 
-
     public List<InvoiceModelDao> getUnpaidInvoicesByAccountFromTransaction(final List<InvoiceModelDao> invoices, @Nullable final LocalDate upToDate) {
         final Collection<InvoiceModelDao> unpaidInvoices = Collections2.filter(invoices, new Predicate<InvoiceModelDao>() {
             @Override
@@ -224,11 +221,11 @@ public class InvoiceDaoHelper {
     }
 
     public void populateChildren(final InvoiceModelDao invoice, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
-        getInvoiceItemsWithinTransaction(invoice, entitySqlDaoWrapperFactory, context);
-        getInvoicePaymentsWithinTransaction(invoice, entitySqlDaoWrapperFactory, context);
+        getInvoiceItemsWithinTransaction(ImmutableList.<InvoiceModelDao>of(invoice), entitySqlDaoWrapperFactory, context);
+        getInvoicePaymentsWithinTransaction(ImmutableList.<InvoiceModelDao>of(invoice), entitySqlDaoWrapperFactory, context);
     }
 
-    public void populateChildren(final List<InvoiceModelDao> invoices, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
+    public void populateChildren(final Iterable<InvoiceModelDao> invoices, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
         getInvoiceItemsWithinTransaction(invoices, entitySqlDaoWrapperFactory, context);
         getInvoicePaymentsWithinTransaction(invoices, entitySqlDaoWrapperFactory, context);
     }
@@ -244,37 +241,49 @@ public class InvoiceDaoHelper {
         return amount == null ? BigDecimal.ZERO : amount;
     }
 
-    private void getInvoiceItemsWithinTransaction(final List<InvoiceModelDao> invoices, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
-        for (final InvoiceModelDao invoice : invoices) {
-            getInvoiceItemsWithinTransaction(invoice, entitySqlDaoWrapperFactory, context);
-        }
-    }
-
-    private void getInvoiceItemsWithinTransaction(final InvoiceModelDao invoice, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
-        final String invoiceId = invoice.getId().toString();
+    private void getInvoiceItemsWithinTransaction(final Iterable<InvoiceModelDao> invoices, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
+        final InvoiceItemSqlDao invoiceItemSqlDao = entitySqlDaoWrapperFactory.become(InvoiceItemSqlDao.class);
+        final List<InvoiceItemModelDao> invoiceItemsForAccount = invoiceItemSqlDao.getByAccountRecordId(context);
 
-        final InvoiceItemSqlDao transInvoiceItemSqlDao = entitySqlDaoWrapperFactory.become(InvoiceItemSqlDao.class);
-        final List<InvoiceItemModelDao> items = transInvoiceItemSqlDao.getInvoiceItemsByInvoice(invoiceId, context);
-        invoice.addInvoiceItems(items);
-    }
+        final Map<UUID, List<InvoiceItemModelDao>> invoiceItemsPerInvoiceId = new HashMap<UUID, List<InvoiceItemModelDao>>();
+        for (final InvoiceItemModelDao item : invoiceItemsForAccount) {
+            if (invoiceItemsPerInvoiceId.get(item.getInvoiceId()) == null) {
+                invoiceItemsPerInvoiceId.put(item.getInvoiceId(), new LinkedList<InvoiceItemModelDao>());
+            }
+            invoiceItemsPerInvoiceId.get(item.getInvoiceId()).add(item);
+        }
 
-    private void getInvoicePaymentsWithinTransaction(final List<InvoiceModelDao> invoices, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
         for (final InvoiceModelDao invoice : invoices) {
-            getInvoicePaymentsWithinTransaction(invoice, entitySqlDaoWrapperFactory, context);
+            // Make sure to set invoice items to a non-null value
+            final List<InvoiceItemModelDao> invoiceItemsForInvoice = Objects.firstNonNull(invoiceItemsPerInvoiceId.get(invoice.getId()), ImmutableList.<InvoiceItemModelDao>of());
+            invoice.addInvoiceItems(invoiceItemsForInvoice);
         }
     }
 
-    private void getInvoicePaymentsWithinTransaction(final InvoiceModelDao invoice, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
+    private void getInvoicePaymentsWithinTransaction(final Iterable<InvoiceModelDao> invoices, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalTenantContext context) {
         final InvoicePaymentSqlDao invoicePaymentSqlDao = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class);
-        final String invoiceId = invoice.getId().toString();
-        final List<InvoicePaymentModelDao> invoicePayments = invoicePaymentSqlDao.getPaymentsForInvoice(invoiceId, context);
-        for (final InvoicePaymentModelDao cur : invoicePayments) {
-            if (cur.getCurrency() != cur.getProcessedCurrency()) {
-                // If any entry is set with a different processed currency, we use it as a processed currency.
-                invoice.setProcessedCurrency(cur.getProcessedCurrency());
-                break;
+        final List<InvoicePaymentModelDao> invoicePaymentsForAccount = invoicePaymentSqlDao.getByAccountRecordId(context);
+
+        final Map<UUID, List<InvoicePaymentModelDao>> invoicePaymentsPerInvoiceId = new HashMap<UUID, List<InvoicePaymentModelDao>>();
+        for (final InvoicePaymentModelDao invoicePayment : invoicePaymentsForAccount) {
+            if (invoicePaymentsPerInvoiceId.get(invoicePayment.getInvoiceId()) == null) {
+                invoicePaymentsPerInvoiceId.put(invoicePayment.getInvoiceId(), new LinkedList<InvoicePaymentModelDao>());
+            }
+            invoicePaymentsPerInvoiceId.get(invoicePayment.getInvoiceId()).add(invoicePayment);
+        }
+
+        for (final InvoiceModelDao invoice : invoices) {
+            // Make sure to set payments to a non-null value
+            final List<InvoicePaymentModelDao> invoicePaymentsForInvoice = Objects.firstNonNull(invoicePaymentsPerInvoiceId.get(invoice.getId()), ImmutableList.<InvoicePaymentModelDao>of());
+            invoice.addPayments(invoicePaymentsForInvoice);
+
+            for (final InvoicePaymentModelDao invoicePayment : invoicePaymentsForInvoice) {
+                if (invoicePayment.getCurrency() != invoicePayment.getProcessedCurrency()) {
+                    // If any entry is set with a different processed currency, we use it as a processed currency.
+                    invoice.setProcessedCurrency(invoicePayment.getProcessedCurrency());
+                    break;
+                }
             }
         }
-        invoice.addPayments(invoicePayments);
     }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index 00d3c1e..9dc4d55 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -30,6 +30,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
+import com.ning.billing.callcontext.InternalTenantContext;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.InvoiceTestSuiteWithEmbeddedDB;
 import com.ning.billing.invoice.api.Invoice;
@@ -70,7 +71,8 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
         Assert.assertNotNull(migrationInvoiceId);
         //Double check it was created and values are correct
 
-        final InvoiceModelDao invoice = invoiceDao.getById(migrationInvoiceId, internalCallContext);
+        final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, callContext);
+        final InvoiceModelDao invoice = invoiceDao.getById(migrationInvoiceId, internalTenantContext);
         Assert.assertNotNull(invoice);
 
         Assert.assertEquals(invoice.getAccountId(), accountId);
@@ -111,8 +113,9 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
     // ACCOUNT balance should reflect total of migration and non-migration invoices
     @Test(groups = "slow")
     public void testBalance() throws InvoiceApiException {
-        final InvoiceModelDao migrationInvoice = invoiceDao.getById(migrationInvoiceId, internalCallContext);
-        final InvoiceModelDao regularInvoice = invoiceDao.getById(regularInvoiceId, internalCallContext);
+        final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, callContext);
+        final InvoiceModelDao migrationInvoice = invoiceDao.getById(migrationInvoiceId, internalTenantContext);
+        final InvoiceModelDao regularInvoice = invoiceDao.getById(regularInvoiceId, internalTenantContext);
         final BigDecimal balanceOfAllInvoices = InvoiceModelDaoHelper.getBalance(migrationInvoice).add(InvoiceModelDaoHelper.getBalance(regularInvoice));
 
         final BigDecimal accountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
index 2ad6556..0488412 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
@@ -712,7 +712,6 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
             assertEquals(cbaAfterRefund.compareTo(expectedCba), 0);
         }
 
-
     }
 
     @Test(groups = "slow")
@@ -1412,14 +1411,14 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Verify scenario - no CBA should have been used
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, context).doubleValue(), 10.00);
-        invoiceUtil.verifyInvoice(invoice1.getId(), 10.00, 10.00);
+        invoiceUtil.verifyInvoice(invoice1.getId(), 10.00, 10.00, context);
 
         // Delete the CBA on invoice 1
         invoiceDao.deleteCBA(accountId, invoice1.getId(), creditBalanceAdjInvoiceItem1.getId(), context);
 
         // Verify the result
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, context).doubleValue(), 0.00);
-        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 0.00);
+        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 0.00, context);
     }
 
     @Test(groups = "slow")
@@ -1470,16 +1469,16 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Verify scenario - half of the CBA should have been used
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, context).doubleValue(), 5.00);
-        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 10.00);
-        invoiceUtil.verifyInvoice(invoice2.getId(), 0.00, -5.00);
+        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 10.00, context);
+        invoiceUtil.verifyInvoice(invoice2.getId(), 0.00, -5.00, context);
 
         // Refund Payment before we can deleted CBA
         invoiceDao.createRefund(paymentId, new BigDecimal("10.0"), false, ImmutableMap.<UUID, BigDecimal>of(), UUID.randomUUID(), context);
 
         // Verify all three invoices were affected
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, context).doubleValue(), 0.00);
-        invoiceUtil.verifyInvoice(invoice1.getId(), 5.00, 5.00);
-        invoiceUtil.verifyInvoice(invoice2.getId(), 0.00, -5.00);
+        invoiceUtil.verifyInvoice(invoice1.getId(), 5.00, 5.00, context);
+        invoiceUtil.verifyInvoice(invoice2.getId(), 0.00, -5.00, context);
     }
 
     @Test(groups = "slow")
@@ -1507,7 +1506,6 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         invoiceUtil.createInvoiceItem(repairAdjInvoiceItem, context);
         invoiceUtil.createInvoiceItem(creditBalanceAdjInvoiceItem1, context);
 
-
         final BigDecimal paymentAmount = new BigDecimal("10.00");
         final UUID paymentId = UUID.randomUUID();
 
@@ -1545,17 +1543,17 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Verify scenario - all CBA should have been used
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, context).doubleValue(), 0.00);
-        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 10.00);
-        invoiceUtil.verifyInvoice(invoice2.getId(), 0.00, -5.00);
-        invoiceUtil.verifyInvoice(invoice3.getId(), 0.00, -5.00);
+        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 10.00, context);
+        invoiceUtil.verifyInvoice(invoice2.getId(), 0.00, -5.00, context);
+        invoiceUtil.verifyInvoice(invoice3.getId(), 0.00, -5.00, context);
 
         invoiceDao.createRefund(paymentId, paymentAmount, false, ImmutableMap.<UUID, BigDecimal>of(), UUID.randomUUID(), context);
 
         // Verify all three invoices were affected
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, context).doubleValue(), 0.00);
-        invoiceUtil.verifyInvoice(invoice1.getId(), 10.00, 10.00);
-        invoiceUtil.verifyInvoice(invoice2.getId(), 0.00, -5.00);
-        invoiceUtil.verifyInvoice(invoice3.getId(), 0.00, -5.00);
+        invoiceUtil.verifyInvoice(invoice1.getId(), 10.00, 10.00, context);
+        invoiceUtil.verifyInvoice(invoice2.getId(), 0.00, -5.00, context);
+        invoiceUtil.verifyInvoice(invoice3.getId(), 0.00, -5.00, context);
     }
 
     @Test(groups = "slow")
@@ -1580,7 +1578,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Verify scenario
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, context).doubleValue(), 10.00);
-        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 10.00);
+        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 10.00, context);
 
         // Delete the CBA on invoice 1
         try {
@@ -1592,6 +1590,6 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Verify the result
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, context).doubleValue(), 10.00);
-        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 10.00);
+        invoiceUtil.verifyInvoice(invoice1.getId(), 0.00, 10.00, context);
     }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceHelper.java
index e64ddeb..17c2f2c 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceHelper.java
@@ -82,7 +82,6 @@ import com.google.common.collect.ImmutableMap;
 
 public class TestInvoiceHelper {
 
-
     public static final Currency accountCurrency = Currency.USD;
 
     public static final int NUMBER_OF_DECIMALS = InvoicingConfiguration.getNumberOfDecimals();
@@ -131,7 +130,6 @@ public class TestInvoiceHelper {
     public static final BigDecimal THREE_HUNDRED_AND_SIXTY_FIVE = new BigDecimal("365.0").setScale(NUMBER_OF_DECIMALS);
     public static final BigDecimal THREE_HUNDRED_AND_SIXTY_SIX = new BigDecimal("366.0").setScale(NUMBER_OF_DECIMALS);
 
-
     private final InvoiceGenerator generator;
     private final BillingInternalApi billingApi;
     private final AccountInternalApi accountApi;
@@ -149,7 +147,6 @@ public class TestInvoiceHelper {
     private final InvoicePaymentSqlDao invoicePaymentSqlDao;
     private final InvoiceItemSqlDao invoiceItemSqlDao;
 
-
     @Inject
     public TestInvoiceHelper(final InvoiceGenerator generator, final IDBI dbi,
                              final BillingInternalApi billingApi, final AccountInternalApi accountApi, final AccountUserApi accountUserApi, final SubscriptionBaseInternalApi subscriptionApi, final BusService busService,
@@ -283,8 +280,8 @@ public class TestInvoiceHelper {
         }
     }
 
-    public void verifyInvoice(final UUID invoiceId, final double balance, final double cbaAmount) throws InvoiceApiException {
-        final InvoiceModelDao invoice = invoiceDao.getById(invoiceId, internalCallContext);
+    public void verifyInvoice(final UUID invoiceId, final double balance, final double cbaAmount, final InternalTenantContext context) throws InvoiceApiException {
+        final InvoiceModelDao invoice = invoiceDao.getById(invoiceId, context);
         Assert.assertEquals(InvoiceModelDaoHelper.getBalance(invoice).doubleValue(), balance);
         Assert.assertEquals(InvoiceModelDaoHelper.getCBAAmount(invoice).doubleValue(), cbaAmount);
     }