killbill-aplcache

invoice: don't retrieve created objects after batch operation Signed-off-by:

2/4/2019 5:46:06 AM

Details

diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index bf84173..252e4ae 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -86,6 +86,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
@@ -309,20 +310,21 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                               final FutureAccountNotifications callbackDateTimePerSubscriptions,
                               final ExistingInvoiceMetadata existingInvoiceMetadata,
                               final InternalCallContext context) {
-        createInvoices(ImmutableList.<InvoiceModelDao>of(invoice), trackingIds, callbackDateTimePerSubscriptions, existingInvoiceMetadata, context);
+        createInvoices(ImmutableList.<InvoiceModelDao>of(invoice), trackingIds, callbackDateTimePerSubscriptions, existingInvoiceMetadata, false, context);
     }
 
     @Override
     public List<InvoiceItemModelDao> createInvoices(final List<InvoiceModelDao> invoices,
                                                     final Set<InvoiceTrackingModelDao> trackingIds,
                                                     final InternalCallContext context) {
-        return createInvoices(invoices, trackingIds, new FutureAccountNotifications(), null, context);
+        return createInvoices(invoices, trackingIds, new FutureAccountNotifications(), null, true, context);
     }
 
     private List<InvoiceItemModelDao> createInvoices(final Iterable<InvoiceModelDao> invoices,
                                                      final Set<InvoiceTrackingModelDao> trackingIds,
                                                      final FutureAccountNotifications callbackDateTimePerSubscriptions,
                                                      @Nullable final ExistingInvoiceMetadata existingInvoiceMetadataOrNull,
+                                                     final boolean returnCreatedInvoiceItems,
                                                      final InternalCallContext context) {
         // Track invoices that are being created
         final Collection<UUID> createdInvoiceIds = new HashSet<UUID>();
@@ -361,7 +363,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                     existingInvoiceMetadata = existingInvoiceMetadataOrNull;
                 }
 
-                final List<InvoiceItemModelDao> invoiceItemsToCreate = new LinkedList<InvoiceItemModelDao>();
+                final Collection<InvoiceItemModelDao> invoiceItemsToCreate = new LinkedList<InvoiceItemModelDao>();
                 for (final InvoiceModelDao invoiceModelDao : invoices) {
                     invoiceByInvoiceId.put(invoiceModelDao.getId(), invoiceModelDao);
                     final boolean isNotShellInvoice = invoiceIdsReferencedFromItems.remove(invoiceModelDao.getId());
@@ -414,7 +416,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                 }
 
                 // Bulk insert the invoice items
-                final List<InvoiceItemModelDao> createdInvoiceItems = createInvoiceItemsFromTransaction(transInvoiceItemSqlDao, invoiceItemsToCreate, context);
+                createInvoiceItemsFromTransaction(transInvoiceItemSqlDao, invoiceItemsToCreate, context);
 
                 for (final UUID adjustedInvoiceId : allInvoiceIds) {
                     final boolean newInvoice = createdInvoiceIds.contains(adjustedInvoiceId);
@@ -438,7 +440,22 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                     trackingIdsSqlDao.create(trackingIds, context);
                 }
 
-                return createdInvoiceItems;
+                if (returnCreatedInvoiceItems) {
+                    if (invoiceItemsToCreate.isEmpty()) {
+                        return ImmutableList.<InvoiceItemModelDao>of();
+                    } else {
+                        return transInvoiceItemSqlDao.getByIds(Collections2.<InvoiceItemModelDao, String>transform(invoiceItemsToCreate,
+                                                                                                                   new Function<InvoiceItemModelDao, String>() {
+                                                                                                                       @Override
+                                                                                                                       public String apply(final InvoiceItemModelDao input) {
+                                                                                                                           return input.getId().toString();
+                                                                                                                       }
+                                                                                                                   }),
+                                                               context);
+                    }
+                } else {
+                    return null;
+                }
             }
         });
     }
@@ -1134,25 +1151,31 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         }
     }
 
-    private InvoiceItemModelDao createInvoiceItemFromTransaction(final InvoiceItemSqlDao invoiceItemSqlDao,
-                                                                 final InvoiceItemModelDao invoiceItemModelDao,
-                                                                 final InternalCallContext context) throws EntityPersistenceException, InvoiceApiException {
-        return Iterables.<InvoiceItemModelDao>getFirst(createInvoiceItemsFromTransaction(invoiceItemSqlDao, ImmutableList.<InvoiceItemModelDao>of(invoiceItemModelDao), context), null);
+    private void createInvoiceItemFromTransaction(final InvoiceItemSqlDao invoiceItemSqlDao,
+                                                  final InvoiceItemModelDao invoiceItemModelDao,
+                                                  final InternalCallContext context) throws EntityPersistenceException, InvoiceApiException {
+        validateInvoiceItemToBeAdjustedIfNeeded(invoiceItemSqlDao, invoiceItemModelDao, context);
+
+        createAndRefresh(invoiceItemSqlDao, invoiceItemModelDao, context);
     }
 
-    private List<InvoiceItemModelDao> createInvoiceItemsFromTransaction(final InvoiceItemSqlDao invoiceItemSqlDao,
-                                                                        final Iterable<InvoiceItemModelDao> invoiceItemModelDaos,
-                                                                        final InternalCallContext context) throws EntityPersistenceException, InvoiceApiException {
+    private void createInvoiceItemsFromTransaction(final InvoiceItemSqlDao invoiceItemSqlDao,
+                                                   final Iterable<InvoiceItemModelDao> invoiceItemModelDaos,
+                                                   final InternalCallContext context) throws EntityPersistenceException, InvoiceApiException {
         for (final InvoiceItemModelDao invoiceItemModelDao : invoiceItemModelDaos) {
-            // There is no efficient way to retrieve an invoice item given an ID today (and invoice plugins can put item adjustments
-            // on a different invoice than the original item), so it's easier to do the check in the DAO rather than in the API layer
-            // See also https://github.com/killbill/killbill/issues/7
-            if (InvoiceItemType.ITEM_ADJ.equals(invoiceItemModelDao.getType())) {
-                validateInvoiceItemToBeAdjusted(invoiceItemSqlDao, invoiceItemModelDao, context);
-            }
+            validateInvoiceItemToBeAdjustedIfNeeded(invoiceItemSqlDao, invoiceItemModelDao, context);
         }
 
-        return createAndRefresh(invoiceItemSqlDao, invoiceItemModelDaos, context);
+        bulkCreate(invoiceItemSqlDao, invoiceItemModelDaos, context);
+    }
+
+    private void validateInvoiceItemToBeAdjustedIfNeeded(final InvoiceItemSqlDao invoiceItemSqlDao, final InvoiceItemModelDao invoiceItemModelDao, final InternalCallContext context) throws InvoiceApiException {
+        // There is no efficient way to retrieve an invoice item given an ID today (and invoice plugins can put item adjustments
+        // on a different invoice than the original item), so it's easier to do the check in the DAO rather than in the API layer
+        // See also https://github.com/killbill/killbill/issues/7
+        if (InvoiceItemType.ITEM_ADJ.equals(invoiceItemModelDao.getType())) {
+            validateInvoiceItemToBeAdjusted(invoiceItemSqlDao, invoiceItemModelDao, context);
+        }
     }
 
     private void validateInvoiceItemToBeAdjusted(final InvoiceItemSqlDao invoiceItemSqlDao, final InvoiceItemModelDao invoiceItemModelDao, final InternalCallContext context) throws InvoiceApiException {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
index 47fde47..b1533de 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2019 Groupon, Inc
+ * Copyright 2014-2019 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
@@ -19,6 +19,7 @@
 package org.killbill.billing.invoice.dao;
 
 import java.math.BigDecimal;
+import java.util.Collection;
 import java.util.List;
 
 import org.killbill.billing.callcontext.InternalCallContext;
@@ -32,6 +33,7 @@ import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.unstable.BindIn;
 
 @KillBillSqlDaoStringTemplate
 public interface InvoiceItemSqlDao extends EntitySqlDao<InvoiceItemModelDao, InvoiceItem> {
@@ -39,14 +41,14 @@ public interface InvoiceItemSqlDao extends EntitySqlDao<InvoiceItemModelDao, Inv
     @SqlQuery
     List<InvoiceItemModelDao> getInvoiceItemsByInvoice(@Bind("invoiceId") final String invoiceId,
                                                        @SmartBindBean final InternalTenantContext context);
+
     @SqlQuery
     List<InvoiceItemModelDao> getInvoiceItemsBySubscription(@Bind("subscriptionId") final String subscriptionId,
                                                             @SmartBindBean final InternalTenantContext context);
 
-
     @SqlQuery
     List<InvoiceItemModelDao> getAdjustedOrRepairedInvoiceItemsByLinkedId(@Bind("linkedItemId") final String linkedItemId,
-                                                            @SmartBindBean final InternalTenantContext context);
+                                                                          @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
@@ -62,4 +64,8 @@ public interface InvoiceItemSqlDao extends EntitySqlDao<InvoiceItemModelDao, Inv
 
     @SqlQuery
     BigDecimal getAccountCBA(@SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    List<InvoiceItemModelDao> getByIds(@BindIn("ids") final Collection<String> invoiceItemIds,
+                                       @SmartBindBean final InternalTenantContext context);
 }
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
index 8dfc05f..7ac7570 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
@@ -50,6 +50,14 @@ tableValues() ::= <<
 , :createdDate
 >>
 
+getByIds(ids) ::= <<
+select
+  <allTableFields("t.")>
+from <tableName()> t
+where <idField("t.")> in (<ids>)
+<AND_CHECK_TENANT("t.")>
+;
+>>
 
 getInvoiceItemsByInvoice() ::= <<
   SELECT <allTableFields("")>
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntityDaoBase.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntityDaoBase.java
index b92af82..d58c367 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntityDaoBase.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntityDaoBase.java
@@ -28,7 +28,6 @@ import java.util.UUID;
 import org.killbill.billing.BillingExceptionBase;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.entity.EntityPersistenceException;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.DefaultPagination;
 import org.killbill.billing.util.entity.Entity;
@@ -113,18 +112,17 @@ public abstract class EntityDaoBase<M extends EntityModelDao<E>, E extends Entit
         };
     }
 
-    protected <F extends EntityModelDao> F createAndRefresh(final EntitySqlDao transactional, final F entity, final InternalCallContext context) throws EntityPersistenceException {
+    protected <F extends EntityModelDao> F createAndRefresh(final EntitySqlDao transactional, final F entity, final InternalCallContext context) {
         // We have overridden the jDBI return type in EntitySqlDaoWrapperInvocationHandler
         return (F) transactional.create(entity, context);
     }
 
-    protected <F extends EntityModelDao> List<F> createAndRefresh(final EntitySqlDao transactional, final Iterable<F> entities, final InternalCallContext context) throws EntityPersistenceException {
+    protected <F extends EntityModelDao> void bulkCreate(final EntitySqlDao transactional, final Iterable<F> entities, final InternalCallContext context) {
         if (Iterables.<F>isEmpty(entities)) {
-            return ImmutableList.<F>of();
+            return;
         }
 
-        // We have overridden the jDBI return type in EntitySqlDaoWrapperInvocationHandler
-        return (List<F>) transactional.create(entities, context);
+        transactional.create(entities, context);
     }
 
     protected boolean checkEntityAlreadyExists(final EntitySqlDao<M, E> transactional, final M entity, final InternalCallContext context) {
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDao.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDao.java
index f61e7d5..e97d5c3 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDao.java
@@ -53,8 +53,8 @@ public interface EntitySqlDao<M extends EntityModelDao<E>, E extends Entity> ext
     @SqlBatch
     @BatchChunkSize(1000) // Arbitrary value, just a safety mechanism in case of very large datasets
     @Audited(ChangeType.INSERT)
-    public Object create(@SmartBindBean final Iterable<M> entity,
-                         @SmartBindBean final InternalCallContext context);
+    public void create(@SmartBindBean final Iterable<M> entity,
+                       @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     public M getById(@Bind("id") final String id,