From a93a3be83a2edb7579d5e4a726a97ab080075b27 Mon Sep 17 00:00:00 2001
From: kaloyane <kaloyane>
Date: Thu, 7 Apr 2011 13:03:47 +0000
Subject: [PATCH] [LMS-2128] do not create temporary files for image
 transformations, use standard input/output instead

SVN: 20709
---
 .../ConvertToolImageTransformer.java          | 80 +++++++++++++------
 1 file changed, 56 insertions(+), 24 deletions(-)

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformer.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformer.java
index b8f189bc8c7..13c8788752a 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformer.java
@@ -17,11 +17,17 @@
 package ch.systemsx.cisd.openbis.dss.etl.biozentrum;
 
 import java.awt.image.BufferedImage;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.imageio.ImageIO;
 
@@ -34,6 +40,7 @@ import ch.systemsx.cisd.common.concurrent.ConcurrencyUtilities;
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.process.IProcessIOHandler;
 import ch.systemsx.cisd.common.process.ProcessExecutionHelper;
 import ch.systemsx.cisd.common.process.ProcessIOStrategy;
 import ch.systemsx.cisd.common.process.ProcessResult;
@@ -78,21 +85,14 @@ public class ConvertToolImageTransformer implements IImageTransformer
 
     public BufferedImage transform(BufferedImage image)
     {
-        File tmpFile = null;
         try
         {
-            tmpFile = createTempImageFile(image);
-            byte[] output = transform(tmpFile);
+            byte[] input = toByteArray(image);
+            byte[] output = transform(input);
             return toBufferedImage(output);
         } catch (IOException ioex)
         {
             throw CheckedExceptionTunnel.wrapIfNecessary(ioex);
-        } finally
-        {
-            if (tmpFile != null)
-            {
-                tmpFile.delete();
-            }
         }
     }
 
@@ -107,49 +107,81 @@ public class ConvertToolImageTransformer implements IImageTransformer
         return imageReader.readImage(output, null);
     }
 
-    private byte[] transform(File imageFile) throws IOException
+    private byte[] transform(final byte[] input) throws IOException
     {
-        String filePath = imageFile.getAbsolutePath();
 
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        final List<String> errorLines = new ArrayList<String>();
+        ProcessIOStrategy customIOStrategy = createCustomProcessIOStrategy(input, bos, errorLines);
+        
         ProcessResult result =
-                ProcessExecutionHelper.run(getCommandLine(filePath), operationLog, machineLog,
-                        ConcurrencyUtilities.NO_TIMEOUT,
-                        ProcessIOStrategy.BINARY_DISCARD_STDERR_IO_STRATEGY, false);
+                ProcessExecutionHelper.run(getCommandLine(), operationLog, machineLog,
+                        ConcurrencyUtilities.NO_TIMEOUT, customIOStrategy, false);
 
         if (result.isOK() == false)
         {
+            operationLog.warn("Execution of 'convert' failed. Dumping standard error...\n"
+                    + errorLines.toString());
             throw new IOException(String.format(
-                    "Error calling 'convert' for image '%s'. Exit value: %d, I/O status: %s",
-                    filePath, result.getExitValue(), result.getProcessIOResult().getStatus()));
+                    "Error calling 'convert'. Exit value: %d, I/O status: %s",
+                    result.getExitValue(), result.getProcessIOResult().getStatus()));
         } else
         {
-            return result.getBinaryOutput();
+            return bos.toByteArray();
         }
 
     }
 
+    private ProcessIOStrategy createCustomProcessIOStrategy(final byte[] input,
+            final ByteArrayOutputStream bos, final List<String> errorLines)
+    {
+        return ProcessIOStrategy.createCustom(new IProcessIOHandler()
+            {
+                
+                public void handle(AtomicBoolean processRunning, OutputStream stdin, InputStream stdout,
+                        InputStream stderr) throws IOException
+                {
+                    stdin.write(input);
+                    stdin.flush();
+                    stdin.close();
+
+                    byte[] buffer = new byte[ProcessExecutionHelper.RECOMMENDED_BUFFER_SIZE];
+                    BufferedReader stdErrReader = new BufferedReader(new InputStreamReader(stderr));
+                    while (processRunning.get())
+                    {
+                        ProcessExecutionHelper.readBytesIfAvailable(stdout, bos, buffer, -1, false);
+                        ProcessExecutionHelper.readTextIfAvailable(stdErrReader, errorLines, false);
+                    }
+
+                    ProcessExecutionHelper.readBytesIfAvailable(stdout, bos, buffer, -1, false);
+                    ProcessExecutionHelper.readTextIfAvailable(stdErrReader, errorLines, false);
+                }
+            });
+    }
+
     private List<String> parseCommandArguments(String argsString)
     {
         String[] arguments = argsString.trim().split("\\s");
         return Arrays.asList(arguments);
     }
 
-    private List<String> getCommandLine(String filePath)
+    private List<String> getCommandLine()
     {
         ArrayList<String> result = new ArrayList<String>();
         result.add(convertUtilityOrNull.getPath());
         result.addAll(convertCliArguments);
-        result.add(filePath);
+        // use standard input to read image
+        result.add("-");
+        // use standard output to produce result
         result.add("png:-");
         return result;
     }
 
-    private File createTempImageFile(BufferedImage image) throws IOException
+    private byte[] toByteArray(BufferedImage image) throws IOException
     {
-        File tmpFile = File.createTempFile(getClass().getSimpleName(), PNG);
-        tmpFile.deleteOnExit();
-        ImageIO.write(image, PNG, tmpFile);
-        return tmpFile;
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ImageIO.write(image, PNG, bos);
+        return bos.toByteArray();
     }
 
 }
-- 
GitLab