From cb8abe1f6b83d5809b638a1447f48ea3b38afc90 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Tue, 23 Nov 2010 13:14:40 +0000
Subject: [PATCH] LMS-1888 API extended

SVN: 18876
---
 .../server/DssServiceRpcScreening.java        |  42 +++-
 .../server/DssServiceRpcScreeningLogger.java  |  16 ++
 .../api/v1/IDssServiceRpcScreening.java       |  40 ++-
 .../client/api/v1/IPlateImageHandler.java     |  32 +++
 .../v1/IScreeningOpenbisServiceFacade.java    |  13 +
 .../api/v1/ScreeningClientApiTester.java      | 233 ++++++++++++++++++
 .../api/v1/ScreeningOpenbisServiceFacade.java |  29 +++
 7 files changed, 392 insertions(+), 13 deletions(-)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IPlateImageHandler.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningClientApiTester.java

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
index 4f3ccaa2a10..b2f6dc823d4 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
@@ -340,6 +340,19 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc<IDssServiceRpc
 
     public InputStream loadImages(String sessionToken, List<PlateImageReference> imageReferences,
             boolean convertToPng)
+    {
+        Size thumbnailSizeOrNull = null;
+        return loadImages(sessionToken, imageReferences, thumbnailSizeOrNull, convertToPng);
+    }
+
+    public InputStream loadImages(String sessionToken, List<PlateImageReference> imageReferences,
+            ImageSize thumbnailSizeOrNull)
+    {
+        return loadImages(sessionToken, imageReferences, convertToSize(thumbnailSizeOrNull), true);
+    }
+
+    public InputStream loadImages(String sessionToken, List<PlateImageReference> imageReferences,
+            Size sizeOrNull, boolean convertToPng)
     {
         checkDatasetsAuthorizationForIDatasetIdentifier(sessionToken, imageReferences);
         final Map<String, IHCSImageDatasetLoader> imageLoadersMap =
@@ -351,12 +364,13 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc<IDssServiceRpc
                     imageLoadersMap.get(imageReference.getDatasetCode());
             assert imageAccessor != null : "imageAccessor not found for: " + imageReference;
             IContent content =
-                    tryGetImageContent(imageAccessor, imageReference, null, convertToPng);
+                    tryGetImageContent(imageAccessor, imageReference, sizeOrNull, convertToPng);
             imageContents.add(content);
         }
         return new ConcatenatedContentInputStream(true, imageContents);
     }
 
+
     public InputStream loadImages(String sessionToken, List<PlateImageReference> imageReferences)
     {
         return loadImages(sessionToken, imageReferences, true);
@@ -370,11 +384,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc<IDssServiceRpc
         IHCSImageDatasetLoader imageAccessor = createImageLoader(datasetCode, rootDir);
         List<PlateImageReference> imageReferences =
                 createPlateImageReferences(imageAccessor, dataSetIdentifier, wellPositions, channel);
-        Size size = null;
-        if (thumbnailSizeOrNull != null)
-        {
-            size = new Size(thumbnailSizeOrNull.getWidth(), thumbnailSizeOrNull.getHeight());
-        }
+        Size size = convertToSize(thumbnailSizeOrNull);
         List<IContent> imageContents = new ArrayList<IContent>();
         for (PlateImageReference imageReference : imageReferences)
         {
@@ -384,6 +394,15 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc<IDssServiceRpc
         return new ConcatenatedContentInputStream(true, imageContents);
     }
 
+    public List<PlateImageReference> listPlateImageReferences(String sessionToken,
+            IDatasetIdentifier dataSetIdentifier, List<WellPosition> wellPositions, String channel)
+    {
+        String datasetCode = dataSetIdentifier.getDatasetCode();
+        File rootDir = getRootDirectoryForDataSet(datasetCode);
+        IHCSImageDatasetLoader imageAccessor = createImageLoader(datasetCode, rootDir);
+        return createPlateImageReferences(imageAccessor, dataSetIdentifier, wellPositions, channel);
+    }
+
     public void saveImageTransformerFactory(String sessionToken,
             List<IDatasetIdentifier> dataSetIdentifiers, String channel,
             IImageTransformerFactory transformerFactory)
@@ -555,7 +574,16 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc<IDssServiceRpc
     {
         return new Location(wellPosition.getWellColumn(), wellPosition.getWellRow());
     }
-
+    
+    private Size convertToSize(ImageSize thumbnailSizeOrNull)
+    {
+        if (thumbnailSizeOrNull == null)
+        {
+            return null;
+        }
+        return new Size(thumbnailSizeOrNull.getWidth(), thumbnailSizeOrNull.getHeight());
+    }
+    
     private IHCSImageDatasetLoader createImageLoader(String datasetCode)
     {
         File datasetRoot = getRootDirectoryForDataSet(datasetCode);
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningLogger.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningLogger.java
index 01a82367e4b..4feeeafe408 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningLogger.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningLogger.java
@@ -100,6 +100,14 @@ public class DssServiceRpcScreeningLogger extends AbstractServerLogger implement
         return null;
     }
 
+    public InputStream loadImages(String sessionToken, List<PlateImageReference> imageReferences,
+            ImageSize thumbnailSizeOrNull)
+    {
+        logAccess(sessionToken, "load_images", "IMAGE_REFERENCES(%s) SIZE(%s)", imageReferences,
+                thumbnailSizeOrNull);
+        return null;
+    }
+
     public InputStream loadImages(String sessionToken, List<PlateImageReference> imageReferences)
     {
         logAccess(sessionToken, "load_images", "IMAGE_REFERENCES(%s)", imageReferences);
@@ -114,6 +122,14 @@ public class DssServiceRpcScreeningLogger extends AbstractServerLogger implement
         return null;
     }
 
+    public List<PlateImageReference> listPlateImageReferences(String sessionToken,
+            IDatasetIdentifier dataSetIdentifier, List<WellPosition> wellPositions, String channel)
+    {
+        logAccess(sessionToken, "list_plate_image_references", "DATA_SET(%s) CHANNEL(%s)",
+                dataSetIdentifier, channel);
+        return null;
+    }
+
     public void saveImageTransformerFactory(String sessionToken,
             List<IDatasetIdentifier> dataSetIdentifiers, String channel,
             IImageTransformerFactory transformerFactory)
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
index 5c8e86ba0f4..d3d24e918db 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
@@ -133,6 +133,24 @@ public interface IDssServiceRpcScreening extends IRpcService
             @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<PlateImageReference> imageReferences,
             boolean convertToPng);
 
+    /**
+     * Provide images (PNG encoded) for a given list of image references (given by data set code,
+     * well position, channel and tile). The result is encoded into one stream, which consist of
+     * multiple blocks in a format: (<block-size><block-of-bytes>)*, where block-size is the block
+     * size in bytes encoded as one long number. The number of blocks is equal to the number of
+     * specified references and the order of blocks corresponds to the order of image references. If
+     * <code>size</code> is specified, the images will be scaled conserving aspect ratio in order to
+     * fit into specified size. Otherwise images of original size are delivered.
+     * 
+     * @since 1.4
+     */
+    @MinimalMinorVersion(4)
+    @DataSetAccessGuard
+    public InputStream loadImages(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<PlateImageReference> imageReferences,
+            ImageSize size);
+    
     /**
      * Provide images for a given list of image references (given by data set code, well position,
      * channel and tile). The result is encoded into one stream, which consist of multiple blocks in
@@ -147,11 +165,10 @@ public interface IDssServiceRpcScreening extends IRpcService
             @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<PlateImageReference> imageReferences);
 
     /**
-     * Provide images for a specified data set, a list of well positions (empty list means all
-     * wells), a channel, and an optional thumb nail size. Images of all tiles are delivered. If
-     * thumb nail size isn't specified the original image is delivered otherwise a thumb nail image
-     * with same aspect ratio as the original image but which fits into specified size will be
-     * delivered.
+     * Provide images for specified data set, list of well positions (empty list means all wells),
+     * channel, and optional thumb nail size. Images of all tiles are delivered. If thumb nail size
+     * isn't specified the original image is delivered otherwise a thumb nail image with same aspect
+     * ratio as the original image but which fits into specified size will be delivered.
      * <p>
      * The result is encoded into one stream, which consist of multiple blocks in a format:
      * (<block-size><block-of-bytes>)*, where block-size is the block size in bytes encoded as one
@@ -167,7 +184,18 @@ public interface IDssServiceRpcScreening extends IRpcService
             String sessionToken,
             @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
             List<WellPosition> wellPositions, String channel, ImageSize thumbnailSizeOrNull);
-    
+
+    /**
+     * Lists plate image references for specified data set, list of well positions (empty list means
+     * all wells), and channel.
+     */
+    @MinimalMinorVersion(4)
+    @DataSetAccessGuard
+    public List<PlateImageReference> listPlateImageReferences(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
+            List<WellPosition> wellPositions, String channel);
+
     /**
      * Saves the specified transformer factory for the specified channel and the experiment to
      * which the specified data sets belong.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IPlateImageHandler.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IPlateImageHandler.java
new file mode 100644
index 00000000000..6bd36360dac
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IPlateImageHandler.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.plugin.screening.client.api.v1;
+
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateImageReference;
+
+/**
+ * Interface of classes handling bytes PNG-encoded plate images.
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IPlateImageHandler
+{
+    /**
+     * Handles specified image file bytes for specified plate image reference.
+     */
+    public void handlePlateImage(PlateImageReference plateImageReference, byte[] imageFileBytes);
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
index 8731c64f3fe..0bbd3813377 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
@@ -265,6 +265,19 @@ public interface IScreeningOpenbisServiceFacade
             List<WellPosition> wellPositions, String channel, ImageSize thumbnailSizeOrNull)
             throws IOException;
     
+    /**
+     * Loads PNG-encoded images for specified data set, list of well positions (empty
+     * list means all wells), channel, and optional thumb nail size. Images of all tiles are
+     * delivered. If thumb nail size isn't specified the original image is delivered otherwise a
+     * thumb nail image with same aspect ratio as the original image but which fits into specified
+     * size will be delivered.
+     * 
+     * @param plateImageHandler Handles delivered images.
+     */
+    public void loadImages(IDatasetIdentifier datasetIdentifier, List<WellPosition> wellPositions,
+            String channel, ImageSize thumbnailSizeOrNull, IPlateImageHandler plateImageHandler)
+            throws IOException;
+    
     /**
      * Saves the specified transformer factory for the specified channel and the experiment to
      * which the specified data sets belong.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningClientApiTester.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningClientApiTester.java
new file mode 100644
index 00000000000..27c83bac4b9
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningClientApiTester.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.plugin.screening.client.api.v1;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.text.JTextComponent;
+
+import org.apache.log4j.PropertyConfigurator;
+
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.IDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageSize;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateImageReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition;
+
+/**
+ * A test class which shows how to use API.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ScreeningClientApiTester
+{
+    private static final class Form extends JPanel
+    {
+        private final JPanel panel;
+        private final Component parent;
+        private final String title;
+
+        Form(Component parent, String title)
+        {
+            super(new BorderLayout());
+            this.parent = parent;
+            this.title = title;
+            panel = new JPanel();
+            panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+            add(panel, BorderLayout.CENTER);
+        }
+        
+        JTextComponent createTextField(String fieldName, int width, boolean passwordField)
+        {
+            JTextComponent result = passwordField ? new JPasswordField(width) : new JTextField(width);
+            addField(fieldName, result);
+            return result;
+        }
+        
+        void addField(String fieldName, JComponent field)
+        {
+            JPanel fieldPanel = new JPanel(new BorderLayout());
+            JLabel label = new JLabel(fieldName + ":");
+            Dimension preferredSize = label.getPreferredSize();
+            label.setPreferredSize(new Dimension(100, preferredSize.height));
+            fieldPanel.add(label, BorderLayout.WEST);
+            fieldPanel.add(field, BorderLayout.CENTER);
+            panel.add(fieldPanel);
+        }
+        
+        void showForm()
+        {
+            JOptionPane.showMessageDialog(parent, this, title, JOptionPane.QUESTION_MESSAGE);
+        }
+        
+    }
+    
+    private static final class TesterFrame extends JFrame
+    {
+        private static final long serialVersionUID = 1L;
+        
+        private IScreeningOpenbisServiceFacade facade;
+
+        private JPanel content;
+        
+        TesterFrame()
+        {
+            setTitle("Screening API Tester");
+            setSize(800, 600);
+            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+            Container contentPane = getContentPane();
+            
+            content = new JPanel();
+            content.setLayout(new BorderLayout());
+            JScrollPane scrollPane = new JScrollPane(content);
+            contentPane.add(scrollPane);
+            
+            JMenuBar menuBar = new JMenuBar();
+            setJMenuBar(menuBar);
+            JMenu callApiMenu = new JMenu("Call API");
+            menuBar.add(callApiMenu);
+            JMenuItem loadImagesByDataSetMenu = new JMenuItem("Load images by data set code");
+            callApiMenu.add(loadImagesByDataSetMenu);
+            loadImagesByDataSetMenu.addActionListener(new ActionListener()
+                {
+                    public void actionPerformed(ActionEvent e)
+                    {
+                        loadImagesByDataSetCode();
+                    }
+                });
+        }
+        
+        void setUp(String[] args)
+        {
+            setVisible(true);
+            if (args.length == 3)
+            {
+                facade = ScreeningOpenbisServiceFacadeFactory.tryCreate(args[0], args[1], args[2]);
+            } else
+            {
+                Form form = new Form(this, "Connection to openBIS");
+                JTextField url = new JTextField(20);
+                JTextField user = new JTextField(20);
+                JTextField password = new JPasswordField(20);
+                form.addField("Base URL", url);
+                form.addField("User ID", user);
+                form.addField("Password", password);
+                form.showForm();
+                facade = ScreeningOpenbisServiceFacadeFactory.tryCreate(user.getText(), user.getText(), url.getText());
+                if (facade == null)
+                {
+                    throw new RuntimeException("Couldn't connect openBIS.");
+                }
+                JOptionPane.showMessageDialog(this, "Successfully connected to openBIS.");
+            }
+        }
+        
+        private void loadImagesByDataSetCode()
+        {
+            Form form = new Form(this, "Parameters for Loading Images by Data Set");
+            JTextComponent dataSetField = form.createTextField("Data Set", 20, false);
+            JTextComponent wellsField = form.createTextField("Wells", 20, false);
+            JTextComponent channelField = form.createTextField("Channel", 20, false);
+            form.showForm();
+            String dataSetCode = dataSetField.getText();
+            List<IDatasetIdentifier> datasetIdentifiers = facade.getDatasetIdentifiers(Arrays.asList(dataSetCode));
+            if (datasetIdentifiers.isEmpty())
+            {
+                JOptionPane.showMessageDialog(this, "Unkown data set: " + dataSetCode);
+            }
+            List<WellPosition> wellPositions = WellPosition.parseWellPositions(wellsField.getText());
+            try
+            {
+                content.removeAll();
+                final JPanel imagePanel = new JPanel();
+                imagePanel.setLayout(new BoxLayout(imagePanel, BoxLayout.Y_AXIS));
+                content.add(imagePanel, BorderLayout.CENTER);
+                facade.loadImages(datasetIdentifiers.get(0), wellPositions, channelField.getText(), new ImageSize(
+                        200, 100), new IPlateImageHandler()
+                    {
+                        public void handlePlateImage(PlateImageReference plateImageReference,
+                                byte[] imageFileBytes)
+                        {
+                            System.out.println(new Date() + " handle " + plateImageReference);
+                            JLabel image =
+                                    new JLabel(plateImageReference.toString(), new ImageIcon(
+                                            imageFileBytes), SwingConstants.LEFT);
+                            imagePanel.add(image);
+                            validate(imagePanel);
+                        }
+                    });
+            } catch (Exception ex)
+            {
+                ex.printStackTrace();
+                JOptionPane.showMessageDialog(this, ex.toString());
+            }
+        }
+        
+        private void validate(JComponent component)
+        {
+            component.invalidate();
+            getContentPane().validate();
+        }
+    }
+    
+    public static void main(String[] args) throws IOException
+    {
+        configureLogging();
+        TesterFrame testerFrame = new TesterFrame();
+        try
+        {
+            testerFrame.setUp(args);
+        } catch (Throwable ex)
+        {
+            ex.printStackTrace();
+            JOptionPane.showMessageDialog(testerFrame, ex.toString());
+        }
+    }
+    
+    private static void configureLogging()
+    {
+        Properties props = new Properties();
+        props.put("log4j.appender.STDOUT", "org.apache.log4j.ConsoleAppender");
+        props.put("log4j.appender.STDOUT.layout", "org.apache.log4j.PatternLayout");
+        props.put("log4j.appender.STDOUT.layout.ConversionPattern", "%d %-5p [%t] %c - %m%n");
+        props.put("log4j.rootLogger", "INFO, STDOUT");
+        PropertyConfigurator.configure(props);
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
index 41c71321b47..b9923dc9355 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
@@ -566,6 +566,35 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
         return result;
     }
 
+    public void loadImages(IDatasetIdentifier dataSetIdentifier, List<WellPosition> wellPositions,
+            String channel, ImageSize thumbnailSizeOrNull, IPlateImageHandler plateImageHandler)
+            throws IOException
+    {
+        DssServiceRpcScreeningHolder dssServiceHolder =
+                dssServiceCache.createDssService(dataSetIdentifier.getDatastoreServerUrl());
+        IDssServiceRpcScreening service = dssServiceHolder.getService();
+        List<PlateImageReference> plateImageReferences =
+                service.listPlateImageReferences(sessionToken, dataSetIdentifier, wellPositions,
+                        channel);
+        InputStream stream =
+                service.loadImages(sessionToken, plateImageReferences, thumbnailSizeOrNull);
+        ConcatenatedFileOutputStreamWriter imagesWriter =
+                new ConcatenatedFileOutputStreamWriter(stream);
+        int index = 0;
+        long size;
+        do
+        {
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            size = imagesWriter.writeNextBlock(outputStream);
+            if (size > 0)
+            {
+                plateImageHandler.handlePlateImage(plateImageReferences.get(index),
+                        outputStream.toByteArray());
+            }
+            index++;
+        } while (size >= 0);
+    }
+
     public void saveImageTransformerFactory(List<IDatasetIdentifier> dataSetIdentifiers, String channel,
             IImageTransformerFactory transformerFactory)
     {
-- 
GitLab