killbill-memoizeit

jaxrs: make sure to stream out all records in StreamingOutput When

2/24/2017 3:18:28 PM

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
index 7542220..27168ba 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
@@ -20,6 +20,7 @@ package org.killbill.billing.jaxrs.resources;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.URI;
+import java.util.Iterator;
 import java.util.UUID;
 
 import javax.annotation.Nullable;
@@ -163,31 +164,53 @@ public class AdminResource extends JaxRsResourceBase {
         final StreamingOutput json = new StreamingOutput() {
             @Override
             public void write(final OutputStream output) throws IOException, WebApplicationException {
-                final JsonGenerator generator = mapper.getFactory().createGenerator(output);
-                generator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+                Iterator<BusEventWithMetadata<BusEvent>> busEventsIterator = null;
+                Iterator<NotificationEventWithMetadata<NotificationEvent>> notificationsIterator = null;
+
+                try {
+                    final JsonGenerator generator = mapper.getFactory().createGenerator(output);
+                    generator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+
+                    generator.writeStartObject();
+
+                    if (withBusEvents) {
+                        generator.writeFieldName("busEvents");
+                        generator.writeStartArray();
+                        busEventsIterator = getBusEvents(withInProcessing, withHistory, minDate, maxDate, accountRecordId, tenantRecordId).iterator();
+                        while (busEventsIterator.hasNext()) {
+                            final BusEventWithMetadata<BusEvent> busEvent = busEventsIterator.next();
+                            generator.writeObject(new BusEventWithRichMetadata(busEvent));
+                        }
+                        generator.writeEndArray();
+                    }
 
-                generator.writeStartObject();
+                    if (withNotifications) {
+                        generator.writeFieldName("notifications");
+                        generator.writeStartArray();
 
-                if (withBusEvents) {
-                    generator.writeFieldName("busEvents");
-                    generator.writeStartArray();
-                    for (final BusEventWithMetadata<BusEvent> busEvent : getBusEvents(withInProcessing, withHistory, minDate, maxDate, accountRecordId, tenantRecordId)) {
-                        generator.writeObject(new BusEventWithRichMetadata(busEvent));
+                        notificationsIterator = getNotifications(queueName, serviceName, withInProcessing, withHistory, minDate, maxDate, accountRecordId, tenantRecordId).iterator();
+                        while (notificationsIterator.hasNext()) {
+                            final NotificationEventWithMetadata<NotificationEvent> notification = notificationsIterator.next();
+                            generator.writeObject(notification);
+                        }
+                        generator.writeEndArray();
                     }
-                    generator.writeEndArray();
-                }
 
-                if (withNotifications) {
-                    generator.writeFieldName("notifications");
-                    generator.writeStartArray();
-                    for (final NotificationEventWithMetadata<NotificationEvent> notification : getNotifications(queueName, serviceName, withInProcessing, withHistory, minDate, maxDate, accountRecordId, tenantRecordId)) {
-                        generator.writeObject(notification);
+                    generator.writeEndObject();
+                    generator.close();
+                } finally {
+                    // In case the client goes away (IOException), make sure to close the underlying DB connection
+                    if (busEventsIterator != null) {
+                        while (busEventsIterator.hasNext()) {
+                            busEventsIterator.next();
+                        }
+                    }
+                    if (notificationsIterator != null) {
+                        while (notificationsIterator.hasNext()) {
+                            notificationsIterator.next();
+                        }
                     }
-                    generator.writeEndArray();
                 }
-
-                generator.writeEndObject();
-                generator.close();
             }
         };
 
@@ -242,28 +265,37 @@ public class AdminResource extends JaxRsResourceBase {
 
         // TODO Consider adding a real invoice API post 0.18.x
         final Pagination<Tag> tags = tagUserApi.searchTags(SystemTags.PARK_TAG_DEFINITION_NAME, offset, limit, callContext);
+        final Iterator<Tag> iterator = tags.iterator();
 
         final StreamingOutput json = new StreamingOutput() {
             @Override
             public void write(final OutputStream output) throws IOException, WebApplicationException {
-                final JsonGenerator generator = mapper.getFactory().createGenerator(output);
-                generator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
-
-                generator.writeStartObject();
-                for (final Tag tag : tags) {
-                    final UUID accountId = tag.getObjectId();
-                    try {
-                        invoiceUserApi.triggerInvoiceGeneration(accountId, clock.getUTCToday(), null, callContext);
-                        generator.writeStringField(accountId.toString(), OK);
-                    } catch (final InvoiceApiException e) {
-                        if (e.getCode() != ErrorCode.INVOICE_NOTHING_TO_DO.getCode()) {
-                            log.warn("Unable to trigger invoice generation for accountId='{}'", accountId);
+                try {
+                    final JsonGenerator generator = mapper.getFactory().createGenerator(output);
+                    generator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+
+                    generator.writeStartObject();
+                    while (iterator.hasNext()) {
+                        final Tag tag = iterator.next();
+                        final UUID accountId = tag.getObjectId();
+                        try {
+                            invoiceUserApi.triggerInvoiceGeneration(accountId, clock.getUTCToday(), null, callContext);
+                            generator.writeStringField(accountId.toString(), OK);
+                        } catch (final InvoiceApiException e) {
+                            if (e.getCode() != ErrorCode.INVOICE_NOTHING_TO_DO.getCode()) {
+                                log.warn("Unable to trigger invoice generation for accountId='{}'", accountId);
+                            }
+                            generator.writeStringField(accountId.toString(), ErrorCode.fromCode(e.getCode()).toString());
                         }
-                        generator.writeStringField(accountId.toString(), ErrorCode.fromCode(e.getCode()).toString());
+                    }
+                    generator.writeEndObject();
+                    generator.close();
+                } finally {
+                    // In case the client goes away (IOException), make sure to close the underlying DB connection
+                    while (iterator.hasNext()) {
+                        iterator.next();
                     }
                 }
-                generator.writeEndObject();
-                generator.close();
             }
         };
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
index c61ada1..2a3da40 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -314,18 +314,28 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         final StreamingOutput json = new StreamingOutput() {
             @Override
             public void write(final OutputStream output) throws IOException, WebApplicationException {
-                final JsonGenerator generator = mapper.getFactory().createJsonGenerator(output);
-                generator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
-
-                generator.writeStartArray();
-                for (final E entity : entities) {
-                    final J asJson = toJson.apply(entity);
-                    if (asJson != null) {
-                        generator.writeObject(asJson);
+                final Iterator<E> iterator = entities.iterator();
+
+                try {
+                    final JsonGenerator generator = mapper.getFactory().createGenerator(output);
+                    generator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+
+                    generator.writeStartArray();
+                    while (iterator.hasNext()) {
+                        final E entity = iterator.next();
+                        final J asJson = toJson.apply(entity);
+                        if (asJson != null) {
+                            generator.writeObject(asJson);
+                        }
+                    }
+                    generator.writeEndArray();
+                    generator.close();
+                } finally {
+                    // In case the client goes away (IOException), make sure to close the underlying DB connection
+                    while (iterator.hasNext()) {
+                        iterator.next();
                     }
                 }
-                generator.writeEndArray();
-                generator.close();
             }
         };