# HG changeset patch
# User Antonio Moreno <antonio.moreno@openbravo.com>
# Date 1510825214 -3600
#      Thu Nov 16 10:40:14 2017 +0100
# Node ID 24f70a7ca1428863c3e36d64703a9cc6c6278dd6
# Parent  2cea76ce07e3fc33355290a876b64dfd918a35fa
Fixed issue 37301. Avoid usage of intermediate StringWriters so that response doesn't take too much heap.
The main problem is that the two intermediate StringWriters accumulate the whole response before it is sent back to the client. This causes Java Heap memory problems in case the batching is set to a big amount, and concurrency is high.
The solution is to remove these intermediate StringWriters. We have verified that the messages are not lost even in the case of low level database problems, because the client correctly detects the problem, and doesn't remove the records, and instead tries to send them again in the next synchronization. However, we have added the exception fields in case the import entry fails to be written, because it makes sense to have them properly set.

diff -r 2cea76ce07e3 -r 24f70a7ca142 src/org/openbravo/mobile/core/process/MobileService.java
--- a/src/org/openbravo/mobile/core/process/MobileService.java	Mon Nov 13 11:17:07 2017 +0100
+++ b/src/org/openbravo/mobile/core/process/MobileService.java	Thu Nov 16 10:40:14 2017 +0100
@@ -9,7 +9,6 @@
 package org.openbravo.mobile.core.process;
 
 import java.io.IOException;
-import java.io.StringWriter;
 import java.io.Writer;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -133,17 +132,12 @@
             // first write to a stringwriter
             // if an exception occurs then the exception can be written to a fresh response
             // writer
-            final Writer w = new StringWriter();
+            final Writer w = response.getWriter();
             w.write("{\"response\":{");
             new MobileServiceProcessor().execServiceName(w, pathparts[1], (JSONObject) jsonsent);
             w.write("}}");
             w.close();
 
-            // got here so probably fine to write to the response now
-            final Writer respWriter = response.getWriter();
-            respWriter.write(w.toString());
-            respWriter.close();
-
           } else {
             response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
             writeResult(response, JsonUtils.convertExceptionToJson(new InvalidRequestException(
diff -r 2cea76ce07e3 -r 24f70a7ca142 src/org/openbravo/mobile/core/process/MobileServiceProcessor.java
--- a/src/org/openbravo/mobile/core/process/MobileServiceProcessor.java	Mon Nov 13 11:17:07 2017 +0100
+++ b/src/org/openbravo/mobile/core/process/MobileServiceProcessor.java	Thu Nov 16 10:40:14 2017 +0100
@@ -9,7 +9,6 @@
 package org.openbravo.mobile.core.process;
 
 import java.io.IOException;
-import java.io.StringWriter;
 import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -68,32 +67,13 @@
   public void execServiceName(Writer w, String serviceName, JSONObject jsonsent) throws Exception {
     List<? extends JSONProcess> processes = getServiceClassInstances(serviceName);
 
-    // Create a new writer for each process. Only write on the given writer the last execution
-    // result.
-    Writer tmpwriter = null;
-    int i = 0;
     for (JSONProcess process : processes) {
-      i++;
-      tmpwriter = new StringWriter();
-      try {
-        execProcess(tmpwriter, process, jsonsent);
-      } catch (Exception e) {
-        if (processes.size() == i
-            || (process instanceof SecuredJSONProcess && !((SecuredJSONProcess) process)
-                .executeNextServiceClassOnFailure())) {
-          tmpwriter.close();
-          throw e;
-        }
-      }
-      tmpwriter.close();
+      execProcess(w, process, jsonsent);
       if (!(process instanceof SecuredJSONProcess && ((SecuredJSONProcess) process)
           .executeNextServiceClass())) {
         break;
       }
     }
-    if (tmpwriter != null) {
-      w.write(tmpwriter.toString());
-    }
   }
 
   /**
@@ -112,7 +92,12 @@
     if (process instanceof SecuredJSONProcess) {
       if (!synchronizedMode && !bypassImportEntry
           && process instanceof DataSynchronizationImportProcess) {
-        ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent);
+        try {
+          ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent);
+        } catch (Exception e) {
+          log.error(this.getClass().getName() + ": Error when creating ImportEntry: ", e);
+          JSONRowConverter.addJSONExceptionFields(w, e);
+        }
       } else {
         ((SecuredJSONProcess) process).secureExec(w, jsonsent);
       }
