From 0fb64fd99679448315dea09c067b2c258d39f5fb Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Mon, 22 Nov 2010 14:48:05 +0000
Subject: [PATCH] LMS-1888 adding a imageTransformerFactory signature to the
 image URLs in order to distinguish images. Helps to avoid problems caused by
 image caching in Web browsers.

SVN: 18844
---
 .../server/AbstractImagesDownloadServlet.java | 18 ++++++++----
 .../detailviewers/ImageUrlUtils.java          |  5 ++++
 .../application/detailviewers/WellImages.java |  6 ++++
 .../detailviewers/heatmaps/PlateLayouter.java | 25 ++++++++++++++--
 .../basic/dto/DatasetImagesReference.java     |  5 ++++
 .../basic/dto/PlateImageParameters.java       | 14 +++++++++
 .../shared/imaging/HCSDatasetLoader.java      | 29 ++++++++++++++++---
 7 files changed, 90 insertions(+), 12 deletions(-)

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractImagesDownloadServlet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractImagesDownloadServlet.java
index 327264e035c..fb2200c4356 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractImagesDownloadServlet.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractImagesDownloadServlet.java
@@ -152,21 +152,29 @@ abstract class AbstractImagesDownloadServlet extends AbstractDatasetDownloadServ
     protected final void doGet(final HttpServletRequest request, final HttpServletResponse response)
             throws ServletException, IOException
     {
+        TileImageReference reference = null;
         try
         {
-            TileImageReference params = RequestParams.createTileImageReference(request);
-            HttpSession session = tryGetOrCreateSession(request, params.getSessionId());
+            reference = RequestParams.createTileImageReference(request);
+            HttpSession session = tryGetOrCreateSession(request, reference.getSessionId());
             if (session == null)
             {
                 printSessionExpired(response);
             } else
             {
-                deliverFile(response, params, session);
+                deliverFile(response, reference, session);
             }
         } catch (Exception e)
         {
-            //e.printStackTrace();
-            printErrorResponse(response, "Error: " + e.getMessage());
+            String message = "Error: Couldn't deliver image";
+            if (reference != null)
+            {
+                message +=
+                        " for data set " + reference.getDatasetCode() + " and channel "
+                                + reference.getChannel();
+            }
+            operationLog.error(message, e);
+            printErrorResponse(response, message);
         }
 
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ImageUrlUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ImageUrlUtils.java
index 4e249b680ba..25f6094e084 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ImageUrlUtils.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ImageUrlUtils.java
@@ -104,6 +104,11 @@ public class ImageUrlUtils
         methodWithParameters.addParameter("wellCol", images.getWellLocation().getColumn());
         methodWithParameters.addParameter("tileRow", tileRow);
         methodWithParameters.addParameter("tileCol", tileCol);
+        String signature = images.getTransformerFactorySignatureOrNull(channel);
+        if (signature != null)
+        {
+            methodWithParameters.addParameter("transformerFactorySignature", signature);
+        }
         String linkURL = createImageLinks ? methodWithParameters.toString() : null;
         methodWithParameters.addParameter("mode", "thumbnail" + width + "x" + height);
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellImages.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellImages.java
index cc903c989d2..f8224c7cf88 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellImages.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellImages.java
@@ -91,4 +91,10 @@ public class WellImages
     {
         return getDataset().getDatastoreCode();
     }
+    
+    public String getTransformerFactorySignatureOrNull(String channelCode)
+    {
+        return getImageParams().getTransformerFactorySignatureOrNull(channelCode);
+    }
+    
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/heatmaps/PlateLayouter.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/heatmaps/PlateLayouter.java
index cb9031ab210..49eb90f491b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/heatmaps/PlateLayouter.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/heatmaps/PlateLayouter.java
@@ -36,10 +36,13 @@ import com.extjs.gxt.ui.client.widget.layout.RowLayout;
 import com.extjs.gxt.ui.client.widget.layout.TableLayout;
 import com.google.gwt.user.client.ui.Widget;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.renderer.IRealNumberRenderer;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.renderer.RealNumberRenderer;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.GWTUtils;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMessageProvider;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.IScreeningClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.ScreeningViewContext;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.DefaultChannelState;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.PlateStyleSetter;
@@ -283,15 +286,31 @@ public class PlateLayouter
 
     private static Component createWellWidget(final WellData wellData,
             final DefaultChannelState channelState, final PlateLayouterModel model,
-            final ScreeningViewContext viewContext)
+            final ScreeningViewContext screeningViewContext)
     {
         Component widget = createWellBox(wellData);
+
         widget.addListener(Events.OnMouseDown, new Listener<BaseEvent>()
             {
                 public void handleEvent(BaseEvent ce)
                 {
-                    WellContentDialog.showContentDialog(wellData, model.tryGetImageDataset(),
-                            channelState, viewContext);
+                    IScreeningClientServiceAsync service = screeningViewContext.getService();
+                    // Reload meta data because they might be out dated especially when
+                    // image transformer factory has changed. For the image URL the
+                    // signature of the factory is needed to distinguish them. This is important
+                    // because Web browser cache images.
+                    service.getPlateContentForDataset(new TechId(model.tryGetImageDataset()
+                            .getDatasetId()), new AbstractAsyncCallback<PlateImages>(
+                            screeningViewContext)
+                        {
+                            @Override
+                            protected void process(PlateImages plateContent)
+                            {
+                                DatasetImagesReference ds = plateContent.getImagesDataset();
+                                WellContentDialog.showContentDialog(wellData, ds, channelState,
+                                        screeningViewContext);
+                            }
+                        });
                 }
             });
         widget.sinkEvents(Events.OnMouseDown.getEventCode());
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/DatasetImagesReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/DatasetImagesReference.java
index 8651299b3e6..426ba14a206 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/DatasetImagesReference.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/DatasetImagesReference.java
@@ -60,6 +60,11 @@ public class DatasetImagesReference implements IsSerializable
     {
         return dataset.getCode();
     }
+    
+    public Long getDatasetId()
+    {
+        return dataset.getId();
+    }
 
     public DatasetReference getDatasetReference()
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImageParameters.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImageParameters.java
index 27ae3a545af..7995a4f4340 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImageParameters.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImageParameters.java
@@ -16,7 +16,9 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import com.google.gwt.user.client.rpc.IsSerializable;
 
@@ -42,6 +44,8 @@ public class PlateImageParameters implements IsSerializable
 
     private List<String> channelsLabels;
 
+    private Map<String, String> channelsTransformerFactorySignatures = new HashMap<String, String>();
+
     // true if any well in the dataset has a time series (or depth stack) of images
     private boolean isMultidimensional;
 
@@ -130,4 +134,14 @@ public class PlateImageParameters implements IsSerializable
         return channelsLabels;
     }
 
+    public void addTransformerFactorySignatureFor(String channelCode, String signatureOrNull)
+    {
+        channelsTransformerFactorySignatures.put(channelCode, signatureOrNull);
+    }
+    
+    public String getTransformerFactorySignatureOrNull(String channelCode)
+    {
+        return channelsTransformerFactorySignatures.get(channelCode);
+    }
+
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/HCSDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/HCSDatasetLoader.java
index 9f2b1d0e38a..893f5c48c74 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/HCSDatasetLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/HCSDatasetLoader.java
@@ -21,7 +21,9 @@ import java.util.List;
 
 import org.apache.commons.lang.StringEscapeUtils;
 
+import ch.systemsx.cisd.common.utilities.MD5ChecksumCalculator;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateImageParameters;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellImageChannelStack;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingReadonlyQueryDAO;
@@ -29,6 +31,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgCh
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgChannelStackDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgContainerDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgDatasetDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgExperimentDTO;
 
 /**
  * Helper class for easy handling of HCS image dataset standard structure with no code for handling
@@ -43,12 +46,14 @@ public class HCSDatasetLoader implements IHCSDatasetLoader
 
     protected final ImgDatasetDTO dataset;
 
+    private final String mergedChannelTransformerFactorySignature;
+    
     protected ImgContainerDTO container;
 
     protected Integer channelCount;
 
     protected List<ImgChannelDTO> channels;
-
+    
     public HCSDatasetLoader(IImagingReadonlyQueryDAO query, String datasetPermId)
     {
         this.query = query;
@@ -57,9 +62,11 @@ public class HCSDatasetLoader implements IHCSDatasetLoader
         {
             throw new IllegalStateException(String.format("Dataset '%s' not found", datasetPermId));
         }
+        long experimentId = getContainer().getExperimentId();
+        ImgExperimentDTO experiment = query.tryGetExperimentById(experimentId);
+        mergedChannelTransformerFactorySignature = getSignature(experiment.getSerializedImageTransformerFactory());
         this.channels =
-                query.getChannelsByDatasetIdOrExperimentId(getDataset().getId(), getContainer()
-                        .getExperimentId());
+                query.getChannelsByDatasetIdOrExperimentId(getDataset().getId(), experimentId);
     }
 
     protected final ImgContainerDTO getContainer()
@@ -115,16 +122,30 @@ public class HCSDatasetLoader implements IHCSDatasetLoader
         params.setTileRowsNum(getDataset().getFieldNumberOfRows());
         params.setTileColsNum(getDataset().getFieldNumberOfColumns());
         params.setIsMultidimensional(dataset.getIsMultidimensional());
+        params.addTransformerFactorySignatureFor(ScreeningConstants.MERGED_CHANNELS,
+                mergedChannelTransformerFactorySignature);
         List<String> channelsCodes = new ArrayList<String>();
         List<String> channelsLabels = new ArrayList<String>();
         for (ImgChannelDTO channel : channels)
         {
             // TODO 2010-11-19, IA: is this escaping needed?
-            channelsCodes.add(StringEscapeUtils.escapeCsv(channel.getCode()));
+            String channelCode = StringEscapeUtils.escapeCsv(channel.getCode());
+            channelsCodes.add(channelCode);
             channelsLabels.add(StringEscapeUtils.escapeCsv(channel.getLabel()));
+            params.addTransformerFactorySignatureFor(channelCode, getSignature(channel
+                    .getSerializedImageTransformerFactory()));
         }
         params.setChannelsCodes(channelsCodes);
         params.setChannelsLabels(channelsLabels);
         return params;
     }
+    
+    private String getSignature(byte[] bytesOrNull)
+    {
+        if (bytesOrNull == null)
+        {
+            return null;
+        }
+        return MD5ChecksumCalculator.calculate(bytesOrNull).substring(0, 10);
+    }
 }
\ No newline at end of file
-- 
GitLab