From 8dbaec5133725af6a5b74cc082d7f330d51318a9 Mon Sep 17 00:00:00 2001
From: tpylak <tpylak>
Date: Wed, 21 Apr 2010 09:52:23 +0000
Subject: [PATCH] LMS-1491 screening API: fetching images, API improvements

SVN: 15557
---
 screening/.classpath                          |   1 +
 screening/etc/service.properties              |   6 +-
 .../server/DssScreeningApiServlet.java        |  47 +++++
 .../server/DssServiceRpcScreening.java        | 196 ++++++++++++++++++
 .../shared/api/IDssServiceRpcScreening.java   |  64 ++++++
 .../api/v1/ScreeningOpenbisServiceFacade.java | 161 +++++++++++---
 .../screening/server/ScreeningServer.java     |  26 ++-
 .../server/ScreeningServerLogger.java         |  37 ++--
 .../server/logic/ScreeningApiImpl.java        |  95 +++++++--
 .../shared/api/IGenedataDssServer.java        |  83 --------
 .../shared/api/IScreeningApiServer.java       |  23 +-
 .../ScreenerDatasetPredicate.java             |  44 ----
 .../ScreenerReadonlyPlatePredicate.java       |   6 +-
 .../authorization/ScreenerWellPredicate.java  |  44 ----
 .../screening/shared/api/dto/Dataset.java     |  50 -----
 .../shared/api/dto/DatasetIdentifier.java     |  58 ++++++
 .../shared/api/dto/DatasetReference.java      |  33 +++
 .../dto/FeatureVectorDatasetReference.java    |  34 +++
 .../shared/api/dto/IDatasetIdentifier.java    |  21 +-
 .../dto/IFeatureVectorDatasetIdentifier.java  |  26 +++
 .../api/dto/IImageDatasetIdentifier.java      |  26 +++
 .../shared/api/dto/IPlateIdentifier.java      |  15 --
 .../shared/api/dto/ImageDatasetMetadata.java  |  15 +-
 .../shared/api/dto/ImageDatasetReference.java |  33 +++
 .../screening/shared/api/dto/Plate.java       |  27 +--
 .../shared/api/dto/PlateIdentifier.java       |  52 +++++
 .../shared/api/dto/PlateImageReference.java   |  53 +++++
 .../shared/api/dto/PlateSingleImage.java      |  22 +-
 .../shared/api/dto/WellFeaturesReference.java |  35 ----
 .../shared/api/dto/WellPosition.java          |   6 +
 .../java/screening-dssApplicationContext.xml  |  36 ++++
 .../screening/ScreeningClientApiTest.java     |  84 +++++++-
 32 files changed, 1056 insertions(+), 403 deletions(-)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DssScreeningApiServlet.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/IDssServiceRpcScreening.java
 delete mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/IGenedataDssServer.java
 delete mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerDatasetPredicate.java
 delete mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerWellPredicate.java
 delete mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/Dataset.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/DatasetIdentifier.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/DatasetReference.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/FeatureVectorDatasetReference.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IFeatureVectorDatasetIdentifier.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IImageDatasetIdentifier.java
 delete mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IPlateIdentifier.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/ImageDatasetReference.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateIdentifier.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateImageReference.java
 delete mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/WellFeaturesReference.java
 create mode 100644 screening/source/java/screening-dssApplicationContext.xml

diff --git a/screening/.classpath b/screening/.classpath
index 4f56ff96ea0..e9814e6ef45 100644
--- a/screening/.classpath
+++ b/screening/.classpath
@@ -38,5 +38,6 @@
 			<attribute name="javadoc_location" value="jar:platform:/resource/libraries/jfreechart/jfreechart-1.0.13-javadocs.zip!/jfreechart-1.0.13-javadocs"/>
 		</attributes>
 	</classpathentry>
+	<classpathentry kind="lib" path="/libraries/spring/third-party/stream-supporting-httpinvoker.jar" sourcepath="/libraries/spring/third-party/stream-supporting-httpinvoker-src.zip"/>
 	<classpathentry kind="output" path="targets/www/WEB-INF/classes"/>
 </classpath>
diff --git a/screening/etc/service.properties b/screening/etc/service.properties
index 36f93e28c1d..79fbef37f27 100644
--- a/screening/etc/service.properties
+++ b/screening/etc/service.properties
@@ -140,7 +140,7 @@ hierarchical-storage-updater.hierarchy-root-dir = targets/hierarchical-store
 # ---------------------------------------------------------------------------
 
 # list of additional web servlets which will be exposed
-plugin-services = screening-image-download-servlet, tabular-data-graph-servlet
+plugin-services = screening-image-download-servlet, tabular-data-graph-servlet, screening-dss-api-exporter-servlet
 # class of the web servlet
 #screening-image-download-servlet.class = ch.systemsx.cisd.openbis.dss.generic.server.MergingImagesDownloadServlet
 screening-image-download-servlet.class = ch.systemsx.cisd.openbis.dss.generic.server.SplittingImagesDownloadServlet
@@ -152,6 +152,10 @@ tabular-data-graph-servlet.class = ch.systemsx.cisd.openbis.dss.generic.server.T
 tabular-data-graph-servlet.path = /datastore_server_graph/*
 tabular-data-graph-servlet.properties-file = etc/tabular-data-graph.properties
 
+# expose an DSS API interface with RPC
+screening-dss-api-exporter-servlet.class = ch.systemsx.cisd.openbis.dss.generic.server.DssScreeningApiServlet
+screening-dss-api-exporter-servlet.path = /rmi-datastore-server-screening-api/*
+
 # ---------------------------------------------------------------------------
 
 # Comma separated names of processing threads. Each thread should have configuration properties prefixed with its name.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DssScreeningApiServlet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DssScreeningApiServlet.java
new file mode 100644
index 00000000000..f30dcb10876
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DssScreeningApiServlet.java
@@ -0,0 +1,47 @@
+/*
+ * 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.dss.generic.server;
+
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import com.marathon.util.spring.StreamSupportingHttpInvokerServiceExporter;
+
+/**
+ * A servlet which exposes the spring bean with the HTTP Invoker
+ * @author Tomasz Pylak
+ */
+public class DssScreeningApiServlet extends HttpInvokerServlet
+{
+    private static final long serialVersionUID = 1L;
+
+    private static final BeanFactory APPLICATION_CONTEXT =
+            new ClassPathXmlApplicationContext(new String[]
+                { "screening-dssApplicationContext.xml" }, true);
+
+    private static StreamSupportingHttpInvokerServiceExporter getDssScreeningService()
+    {
+        return ((StreamSupportingHttpInvokerServiceExporter) APPLICATION_CONTEXT
+                .getBean("data-store-rpc-service-screening"));
+    }
+
+    public DssScreeningApiServlet()
+    {
+        super(getDssScreeningService(), "rmi-screening-dss-api");
+    }
+
+}
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
new file mode 100644
index 00000000000..7bf7c0ec85e
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
@@ -0,0 +1,196 @@
+/*
+ * 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.dss.screening.server;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.List;
+
+import ch.systemsx.cisd.bds.hcs.Geometry;
+import ch.systemsx.cisd.bds.hcs.HCSDatasetLoader;
+import ch.systemsx.cisd.bds.hcs.Location;
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDssServiceRpc;
+import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelsUtils;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
+import ch.systemsx.cisd.openbis.dss.screening.shared.api.IDssServiceRpcScreening;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDataset;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IFeatureVectorDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IImageDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetMetadata;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateImageReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.WellPosition;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
+
+/**
+ * Implementation of the screening API interface using RPC. The instance will be created in spring
+ * and published as a HTTP invoker servlet configured in service.properties.
+ * 
+ * @author Tomasz Pylak
+ */
+public class DssServiceRpcScreening extends AbstractDssServiceRpc implements
+        IDssServiceRpcScreening
+{
+
+    public DssServiceRpcScreening(String storeRootDir)
+    {
+        super(ServiceProvider.getOpenBISService());
+        setStoreDirectory(new File(storeRootDir));
+        operationLog.info("Started RPC V1 screening service.");
+    }
+
+    public int getMinClientVersion()
+    {
+        return 1;
+    }
+
+    public int getVersion()
+    {
+        return 1;
+    }
+
+    // ------------------ impl -----------------
+
+    public List<String> listAvailableFeatureNames(String sessionToken,
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets)
+    {
+        // TODO Auto-generated method stub
+
+        return null;
+    }
+
+    public List<ImageDatasetMetadata> listImageMetadata(String sessionToken,
+            List<? extends IImageDatasetIdentifier> imageDatasets)
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public List<FeatureVectorDataset> loadFeatures(String sessionToken,
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets,
+            List<String> featureNames)
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public InputStream loadImage(String sessionToken, PlateImageReference imageReference)
+    {
+        ExternalData imageDataset =
+                tryFindImageDataset(sessionToken, imageReference.getDatasetCode());
+        if (imageDataset != null)
+        {
+            return getImageStream(imageDataset, imageReference);
+        } else
+        {
+            return null;
+        }
+    }
+
+    private InputStream getImageStream(ExternalData imageDataset, PlateImageReference imageRef)
+    {
+        HCSDatasetLoader imageAccessor = createImageLoader(imageRef.getDatasetCode());
+        Location wellLocation = asLocation(imageRef.getWellPosition());
+        Location tileLocation =
+                getTileLocation(imageRef.getTile(), imageAccessor.getWellGeometry());
+        try
+        {
+            File path =
+                    ImageChannelsUtils.getImagePath(imageAccessor, wellLocation, tileLocation,
+                            imageRef.getChannel());
+            return new FileInputStream(path);
+        } catch (EnvironmentFailureException e)
+        {
+            throw createNoImageException(imageRef);
+        } catch (FileNotFoundException ex)
+        {
+            throw createNoImageException(imageRef);
+        } finally
+        {
+            imageAccessor.close();
+        }
+    }
+
+    private static IllegalArgumentException createNoImageException(PlateImageReference imageRef)
+    {
+        return new IllegalArgumentException("No image found: " + imageRef);
+    }
+
+    private static Location getTileLocation(int tile, Geometry wellGeometry)
+    {
+        int row = ((tile - 1) / wellGeometry.getColumns()) + 1;
+        int col = ((tile - 1) % wellGeometry.getColumns()) + 1;
+        return new Location(row, col);
+    }
+
+    private static Location asLocation(WellPosition wellPosition)
+    {
+        return new Location(wellPosition.getWellColumn(), wellPosition.getWellRow());
+    }
+
+    private HCSDatasetLoader createImageLoader(String datasetCode)
+    {
+        HCSDatasetLoader loader;
+        File datasetRoot = getRootDirectoryForDataSet(datasetCode);
+        loader = new HCSDatasetLoader(datasetRoot);
+        return loader;
+    }
+
+    private ExternalData tryFindImageDataset(String sessionToken, String datasetCode)
+    {
+        ExternalData dataset = tryGetDataSet(sessionToken, datasetCode);
+        if (dataset == null)
+        {
+            throw new IllegalArgumentException("Dataset " + datasetCode + " cannot be found.");
+        }
+        if (isImageDataset(dataset))
+        {
+            return dataset;
+        }
+        // it may be the feature dataset
+        Collection<ExternalData> parents = dataset.getParents();
+        if (parents.size() > 1)
+        {
+            throw new IllegalArgumentException("Dataset " + datasetCode
+                    + " should have at most 1 parent, but has: " + parents.size());
+        }
+        if (parents.size() == 1)
+        {
+            ExternalData parent = parents.iterator().next();
+            if (isImageDataset(parent))
+            {
+                return parent;
+            } else
+            {
+                return null;
+            }
+        } else
+        {
+            return null;
+        }
+    }
+
+    private boolean isImageDataset(ExternalData dataset)
+    {
+        return dataset.getDataSetType().getCode().equals(ScreeningConstants.IMAGE_DATASET_TYPE);
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/IDssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/IDssServiceRpcScreening.java
new file mode 100644
index 00000000000..0c68e4c6e7f
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/IDssServiceRpcScreening.java
@@ -0,0 +1,64 @@
+/*
+ * 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.dss.screening.shared.api;
+
+import java.io.InputStream;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDataset;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IFeatureVectorDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IImageDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetMetadata;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateImageReference;
+
+/**
+ * Public DSS API for screening. Non-compatible changes without consultation are forbidden.
+ * 
+ * @author Tomasz Pylak
+ */
+public interface IDssServiceRpcScreening
+{
+    /**
+     * For a given set of feature vector data sets provide the list of all available features. This
+     * is just the name of the feature. If for different data sets different sets of features are
+     * available, provide the union of the features of all data sets.
+     */
+    List<String> listAvailableFeatureNames(String sessionToken,
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets);
+
+    /**
+     * For a given set of data sets and a set of features (given by their name), provide the feature
+     * matrix. Each column in that matrix is one feature, each row is one well in one data set.
+     */
+    List<FeatureVectorDataset> loadFeatures(String sessionToken,
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets,
+            List<String> featureNames);
+
+    /**
+     * Provide image for a given image reference (given by data set code, well position, channel and
+     * tile).
+     */
+    InputStream loadImage(String sessionToken, PlateImageReference imageReferences);
+
+    /**
+     * For a given set of image data sets, provide all image channels that have been acquired and
+     * the available (natural) image size(s).
+     */
+    List<ImageDatasetMetadata> listImageMetadata(String sessionToken,
+            List<? extends IImageDatasetIdentifier> imageDatasets);
+
+}
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 8fa7b2004df..87100c3d2fb 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
@@ -1,20 +1,28 @@
 package ch.systemsx.cisd.openbis.plugin.screening.client.api.v1;
 
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import ch.systemsx.cisd.common.spring.HttpInvokerUtils;
+import ch.systemsx.cisd.openbis.dss.screening.shared.api.IDssServiceRpcScreening;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.IScreeningApiServer;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Dataset;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDataset;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IDatasetIdentifier;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IPlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IFeatureVectorDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IImageDatasetIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetMetadata;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Plate;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateImageReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateSingleImage;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.WellFeaturesReference;
 
 /**
- * A facade of openBIS and Datastore Server API.
+ * A client side facade of openBIS and Datastore Server API.
  * 
  * @author Tomasz Pylak
  */
@@ -22,7 +30,9 @@ public class ScreeningOpenbisServiceFacade
 {
     private static final int SERVER_TIMEOUT_MIN = 5;
 
-    private final IScreeningApiServer screeningServer;
+    private final IScreeningApiServer openbisScreeningServer;
+
+    private final Map<String/* url */, IDssServiceRpcScreening> dssScreeningServerCache;
 
     private final String sessionToken;
 
@@ -35,31 +45,38 @@ public class ScreeningOpenbisServiceFacade
     public static ScreeningOpenbisServiceFacade tryCreate(String userId, String userPassword,
             String serverUrl)
     {
-        IScreeningApiServer server = createScreeningServer(serverUrl);
-        String sessionToken = server.tryLoginScreening(userId, userPassword);
+        IScreeningApiServer openbisServer = createScreeningOpenbisServer(serverUrl);
+        String sessionToken = openbisServer.tryLoginScreening(userId, userPassword);
         if (sessionToken == null)
         {
             return null;
         }
-        return new ScreeningOpenbisServiceFacade(server, sessionToken);
+        return new ScreeningOpenbisServiceFacade(openbisServer, sessionToken);
     }
 
-    private static IScreeningApiServer createScreeningServer(String serverUrl)
+    private static IScreeningApiServer createScreeningOpenbisServer(String serverUrl)
     {
         return HttpInvokerUtils.createServiceStub(IScreeningApiServer.class, serverUrl
                 + "/rmi-screening-api", SERVER_TIMEOUT_MIN);
     }
 
+    private static IDssServiceRpcScreening createScreeningDssServer(String serverUrl)
+    {
+        return HttpInvokerUtils.createStreamSupportingServiceStub(IDssServiceRpcScreening.class,
+                serverUrl + "/rmi-datastore-server-screening-api", SERVER_TIMEOUT_MIN);
+    }
+
     private ScreeningOpenbisServiceFacade(IScreeningApiServer screeningServer, String sessionToken)
     {
-        this.screeningServer = screeningServer;
+        this.openbisScreeningServer = screeningServer;
+        this.dssScreeningServerCache = new HashMap<String, IDssServiceRpcScreening>();
         this.sessionToken = sessionToken;
     }
 
     /** Closes connection with the server. After calling this method this facade cannot be used. */
     public void logout()
     {
-        screeningServer.logoutScreening(sessionToken);
+        openbisScreeningServer.logoutScreening(sessionToken);
     }
 
     /**
@@ -68,24 +85,34 @@ public class ScreeningOpenbisServiceFacade
      */
     public List<Plate> listPlates()
     {
-        return screeningServer.listPlates(sessionToken);
+        return openbisScreeningServer.listPlates(sessionToken);
     }
 
     /**
      * For a given set of plates provides the list of all connected data sets containing feature
      * vectors.
      */
-    public List<Dataset> listFeatureVectorDatasets(List<? extends IPlateIdentifier> plates)
+    public List<FeatureVectorDatasetReference> listFeatureVectorDatasets(
+            List<? extends PlateIdentifier> plates)
     {
-        return screeningServer.listFeatureVectorDatasets(sessionToken, plates);
+        return openbisScreeningServer.listFeatureVectorDatasets(sessionToken, plates);
     }
 
     /**
      * For a given set of plates provides the list of all connected data sets containing images.
      */
-    public List<Dataset> listImageDatasets(List<? extends IPlateIdentifier> plates)
+    public List<ImageDatasetReference> listImageDatasets(List<? extends PlateIdentifier> plates)
+    {
+        return openbisScreeningServer.listImageDatasets(sessionToken, plates);
+    }
+
+    /**
+     * Converts a given list of dataset codes to dataset identifiers which can be used in other API
+     * calls.
+     */
+    public List<IDatasetIdentifier> getDatasetIdentifiers(List<String> datasetCodes)
     {
-        return screeningServer.listImageDatasets(sessionToken, plates);
+        return openbisScreeningServer.getDatasetIdentifiers(sessionToken, datasetCodes);
     }
 
     /**
@@ -93,34 +120,57 @@ public class ScreeningOpenbisServiceFacade
      * is just the name of the feature. If for different data sets different sets of features are
      * available, provides the union of the feature names of all data sets.
      */
-    public List<String> listAvailableFeatureNames(List<? extends IDatasetIdentifier> featureDatasets)
+    public List<String> listAvailableFeatureNames(
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets)
     {
-        // TODO 2010-04-16, Tomasz Pylak:
-        return null;
+        if (featureDatasets.size() == 0)
+        {
+            return new ArrayList<String>();
+        }
+        IDssServiceRpcScreening dssServer = getScreeningDssServer(featureDatasets);
+        return dssServer.listAvailableFeatureNames(sessionToken, featureDatasets);
     }
 
     /**
      * For a given set of data sets and a set of features (given by their name), provide all the
      * feature vectors.
      */
-    // Q: what result structure do you prefer? The one below is the easiest to use in Java,
-    // but it could be also a simple String[][] table like:
-    // plate-barcode well-row well-column feature1 feature2 ....
     public List<FeatureVectorDataset> loadFeatures(
-            List<? extends IDatasetIdentifier> featureDatasets, List<String> featureNames)
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets,
+            List<String> featureNames)
     {
-        // TODO 2010-04-16, Tomasz Pylak:
-        return null;
+        if (featureDatasets.size() == 0)
+        {
+            return new ArrayList<FeatureVectorDataset>();
+        }
+        if (featureNames.size() == 0)
+        {
+            throw new IllegalArgumentException("no feature names has been specified");
+        }
+        IDssServiceRpcScreening dssServer = getScreeningDssServer(featureDatasets);
+        return dssServer.loadFeatures(sessionToken, featureDatasets, featureNames);
     }
 
     /**
-     * For a given set of wells (given by feature vector data set code and well position), provide
-     * all images for all channels and tiles.
+     * Provide images for a given set of image references (given by data set code, well position,
+     * channel and tile).
      */
-    public List<PlateSingleImage> loadWellImages(List<WellFeaturesReference> wells)
+    public List<PlateSingleImage> loadImages(List<PlateImageReference> imageReferences)
     {
-        // TODO 2010-04-16, Tomasz Pylak:
-        return null;
+        if (imageReferences.size() == 0)
+        {
+            return new ArrayList<PlateSingleImage>();
+        }
+        String datastoreServerUrl = extractDatastoreServerUrl(imageReferences);
+        IDssServiceRpcScreening dssServer = getScreeningDssServer(datastoreServerUrl);
+
+        List<PlateSingleImage> images = new ArrayList<PlateSingleImage>();
+        for (PlateImageReference imageRef : imageReferences)
+        {
+            InputStream stream = dssServer.loadImage(sessionToken, imageRef);
+            images.add(new PlateSingleImage(imageRef, stream));
+        }
+        return images;
     }
 
     /**
@@ -128,10 +178,55 @@ public class ScreeningOpenbisServiceFacade
      * the available (natural) image size(s).
      */
     public List<ImageDatasetMetadata> listImageMetadata(
-            List<? extends IDatasetIdentifier> imageDatasets)
+            List<? extends IImageDatasetIdentifier> imageDatasets)
     {
-        // TODO 2010-04-16, Tomasz Pylak:
-        return null;
+        if (imageDatasets.size() == 0)
+        {
+            return new ArrayList<ImageDatasetMetadata>();
+        }
+        IDssServiceRpcScreening dssServer = getScreeningDssServer(imageDatasets);
+        return dssServer.listImageMetadata(sessionToken, imageDatasets);
     }
 
+    // --------- helpers -----------
+
+    private static String extractDatastoreServerUrl(List<? extends IDatasetIdentifier> datasets)
+    {
+        assert datasets.size() > 0 : "no datasets specified";
+        String datastoreServerUrl = null;
+        for (IDatasetIdentifier dataset : datasets)
+        {
+            String url = dataset.getDatastoreServerUrl();
+            if (datastoreServerUrl == null)
+            {
+                datastoreServerUrl = url;
+            } else
+            {
+                if (datastoreServerUrl.equals(url) == false)
+                {
+                    throw new IllegalArgumentException(
+                            "Only datasets from one datastore server can be specified in one call. Datasets from two different servers have been found.");
+                }
+            }
+        }
+        return datastoreServerUrl;
+    }
+
+    private IDssServiceRpcScreening getScreeningDssServer(String serverUrl)
+    {
+        IDssServiceRpcScreening dssService = dssScreeningServerCache.get(serverUrl);
+        if (dssService == null)
+        {
+            dssService = createScreeningDssServer(serverUrl);
+            dssScreeningServerCache.put(serverUrl, dssService);
+        }
+        return dssService;
+    }
+
+    private IDssServiceRpcScreening getScreeningDssServer(
+            List<? extends IDatasetIdentifier> datasets)
+    {
+        String datastoreServerUrl = extractDatastoreServerUrl(datasets);
+        return getScreeningDssServer(datastoreServerUrl);
+    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
index a2326db3ff6..47b3dfb5119 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
@@ -55,8 +55,10 @@ import ch.systemsx.cisd.openbis.plugin.screening.server.logic.ScreeningApiImpl;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.IScreeningServer;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.ResourceNames;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.IScreeningApiServer;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Dataset;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IPlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDatasetReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Plate;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateContent;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateImages;
@@ -185,8 +187,8 @@ public final class ScreeningServer extends AbstractServer<IScreeningServer> impl
 
     // --------- IScreeningOpenbisServer - method signature should be changed with care
 
-    public List<Dataset> listFeatureVectorDatasets(String sessionToken,
-            List<? extends IPlateIdentifier> plates)
+    public List<FeatureVectorDatasetReference> listFeatureVectorDatasets(String sessionToken,
+            List<? extends PlateIdentifier> plates)
     {
         try
         {
@@ -197,8 +199,8 @@ public final class ScreeningServer extends AbstractServer<IScreeningServer> impl
         }
     }
 
-    public List<Dataset> listImageDatasets(String sessionToken,
-            List<? extends IPlateIdentifier> plates)
+    public List<ImageDatasetReference> listImageDatasets(String sessionToken,
+            List<? extends PlateIdentifier> plates)
     {
         try
         {
@@ -220,6 +222,18 @@ public final class ScreeningServer extends AbstractServer<IScreeningServer> impl
         }
     }
 
+    public List<IDatasetIdentifier> getDatasetIdentifiers(String sessionToken,
+            List<String> datasetCodes)
+    {
+        try
+        {
+            return createScreeningApiImpl(sessionToken).getDatasetIdentifiers(datasetCodes);
+        } catch (UserFailureException e)
+        {
+            throw translateException(e);
+        }
+    }
+
     private ScreeningApiImpl createScreeningApiImpl(String sessionToken)
     {
         try
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServerLogger.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServerLogger.java
index 06f4e0c8ceb..13fb260fab0 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServerLogger.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServerLogger.java
@@ -35,9 +35,11 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.IScreeningServer;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.IScreeningApiServer;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Dataset;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IPlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDatasetReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Plate;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateContent;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateImages;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateSingleImageReference;
@@ -128,17 +130,28 @@ final class ScreeningServerLogger extends AbstractServerLogger implements IScree
         return null;
     }
 
-    // --- IGenedataScreeningServer
+    // --- IScreeningApiServer
 
-    public List<Dataset> listFeatureVectorDatasets(String sessionToken,
-            List<? extends IPlateIdentifier> plates)
+    public void logoutScreening(String sessionToken)
+    {
+        // No logging because already done by the session manager
+    }
+
+    public String tryLoginScreening(String userId, String userPassword)
+    {
+        // No logging because already done by the session manager
+        return null;
+    }
+
+    public List<FeatureVectorDatasetReference> listFeatureVectorDatasets(String sessionToken,
+            List<? extends PlateIdentifier> plates)
     {
         logAccess(sessionToken, "listFeatureVectorDatasets", "plates(%s)", plates);
         return null;
     }
 
-    public List<Dataset> listImageDatasets(String sessionToken,
-            List<? extends IPlateIdentifier> plates)
+    public List<ImageDatasetReference> listImageDatasets(String sessionToken,
+            List<? extends PlateIdentifier> plates)
     {
         logAccess(sessionToken, "listImageDatasets", "plates(%s)", plates);
         return null;
@@ -150,14 +163,10 @@ final class ScreeningServerLogger extends AbstractServerLogger implements IScree
         return null;
     }
 
-    public void logoutScreening(String sessionToken)
+    public List<IDatasetIdentifier> getDatasetIdentifiers(String sessionToken,
+            List<String> datasetCodes)
     {
-        // No logging because already done by the session manager
-    }
-
-    public String tryLoginScreening(String userId, String userPassword)
-    {
-        // No logging because already done by the session manager
+        logAccess(sessionToken, "getDatasetIdentifiers", "datasets(%s)", datasetCodes);
         return null;
     }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java
index d4dd7b2edd8..7d1d8d0774c 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic;
 import java.util.ArrayList;
 import java.util.List;
 
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IExternalDataBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ISampleBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
@@ -30,7 +31,9 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
@@ -40,8 +43,11 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentif
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.translator.SampleTypeTranslator;
 import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Dataset;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IPlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.DatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDatasetReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Plate;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
 
@@ -66,56 +72,90 @@ public class ScreeningApiImpl
         this.daoFactory = daoFactory;
     }
 
-    public List<Dataset> listFeatureVectorDatasets(List<? extends IPlateIdentifier> plates)
+    public List<FeatureVectorDatasetReference> listFeatureVectorDatasets(
+            List<? extends PlateIdentifier> plates)
     {
-        return loadDatasets(plates, ScreeningConstants.IMAGE_ANALYSIS_DATASET_TYPE);
+        List<ExternalDataPE> datasets =
+                loadDatasets(plates, ScreeningConstants.IMAGE_ANALYSIS_DATASET_TYPE);
+        return asFeatureVectorDatasets(datasets);
     }
 
-    public List<Dataset> listImageDatasets(List<? extends IPlateIdentifier> plates)
+    public List<ImageDatasetReference> listImageDatasets(List<? extends PlateIdentifier> plates)
     {
-        return loadDatasets(plates, ScreeningConstants.IMAGE_DATASET_TYPE);
+        List<ExternalDataPE> datasets = loadDatasets(plates, ScreeningConstants.IMAGE_DATASET_TYPE);
+        return asImageDatasets(datasets);
     }
 
     // NOTE: this method is slow when a number of plates is big
-    private List<Dataset> loadDatasets(List<? extends IPlateIdentifier> plates,
+    private List<ExternalDataPE> loadDatasets(List<? extends PlateIdentifier> plates,
             String datasetTypeCode)
     {
         ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
-        List<Dataset> datasets = new ArrayList<Dataset>();
-        for (IPlateIdentifier plate : plates)
+        List<ExternalDataPE> datasets = new ArrayList<ExternalDataPE>();
+        for (PlateIdentifier plate : plates)
         {
-            List<Dataset> plateDatasets = loadDatasets(plate, datasetTypeCode, sampleBO);
+            List<ExternalDataPE> plateDatasets = loadDatasets(plate, datasetTypeCode, sampleBO);
             datasets.addAll(plateDatasets);
         }
         return datasets;
     }
 
-    private List<Dataset> loadDatasets(IPlateIdentifier plate, String datasetTypeCode,
+    private List<ExternalDataPE> loadDatasets(PlateIdentifier plate, String datasetTypeCode,
             ISampleBO sampleBO)
     {
         sampleBO.loadBySampleIdentifier(createSampleIdentifier(plate));
         SamplePE sample = sampleBO.getSample();
         List<ExternalDataPE> datasets = daoFactory.getExternalDataDAO().listExternalData(sample);
         datasets = ScreeningUtils.filterDatasetsByType(datasets, datasetTypeCode);
-        return asDatasets(datasets, plate);
+        return datasets;
+    }
+
+    private static List<FeatureVectorDatasetReference> asFeatureVectorDatasets(
+            List<ExternalDataPE> datasets)
+    {
+        List<FeatureVectorDatasetReference> result = new ArrayList<FeatureVectorDatasetReference>();
+        for (ExternalDataPE externalData : datasets)
+        {
+            result.add(asFeatureVectorDataset(externalData));
+        }
+        return result;
+    }
+
+    private static FeatureVectorDatasetReference asFeatureVectorDataset(ExternalDataPE externalData)
+    {
+        DataStorePE dataStore = externalData.getDataStore();
+        return new FeatureVectorDatasetReference(externalData.getCode(),
+                dataStore.getDownloadUrl(), createPlateIdentifier(externalData));
     }
 
-    private static List<Dataset> asDatasets(List<ExternalDataPE> datasets, IPlateIdentifier plate)
+    private static List<ImageDatasetReference> asImageDatasets(List<ExternalDataPE> datasets)
     {
-        List<Dataset> result = new ArrayList<Dataset>();
+        List<ImageDatasetReference> result = new ArrayList<ImageDatasetReference>();
         for (ExternalDataPE externalData : datasets)
         {
-            result.add(asDataset(externalData, plate));
+            result.add(asImageDataset(externalData));
         }
         return result;
     }
 
-    private static Dataset asDataset(ExternalDataPE externalData, IPlateIdentifier plate)
+    private static ImageDatasetReference asImageDataset(ExternalDataPE externalData)
     {
-        return new Dataset(externalData.getCode(), externalData.getDataStore().getCode(), plate);
+        DataStorePE dataStore = externalData.getDataStore();
+        return new ImageDatasetReference(externalData.getCode(), dataStore.getDownloadUrl(),
+                createPlateIdentifier(externalData));
     }
 
-    private static SampleIdentifier createSampleIdentifier(IPlateIdentifier plate)
+    private static PlateIdentifier createPlateIdentifier(ExternalDataPE externalData)
+    {
+        SamplePE sample = externalData.tryGetSample();
+        assert sample != null : "dataset not connected to a sample: " + externalData;
+        final String plateCode = sample.getCode();
+        GroupPE group = sample.getGroup();
+        final String spaceCodeOrNull = (group != null) ? group.getCode() : null;
+        return new PlateIdentifier(plateCode, spaceCodeOrNull);
+    }
+
+    private static SampleIdentifier createSampleIdentifier(PlateIdentifier plate)
     {
         SampleOwnerIdentifier owner;
         String spaceCode = plate.tryGetSpaceCode();
@@ -171,4 +211,23 @@ public class ScreeningApiImpl
         assert plateTypePE != null : "plate type not found";
         return SampleTypeTranslator.translate(plateTypePE, null);
     }
+
+    public List<IDatasetIdentifier> getDatasetIdentifiers(List<String> datasetCodes)
+    {
+        IExternalDataBO externalDataBO = businessObjectFactory.createExternalDataBO(session);
+        List<IDatasetIdentifier> identifiers = new ArrayList<IDatasetIdentifier>();
+        for (String datasetCode : datasetCodes)
+        {
+            identifiers.add(getDatasetIdentifier(externalDataBO, datasetCode));
+        }
+        return identifiers;
+    }
+
+    private IDatasetIdentifier getDatasetIdentifier(IExternalDataBO externalDataBO,
+            String datasetCode)
+    {
+        externalDataBO.loadByCode(datasetCode);
+        ExternalDataPE externalData = externalDataBO.getExternalData();
+        return new DatasetIdentifier(datasetCode, externalData.getDataStore().getDownloadUrl());
+    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/IGenedataDssServer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/IGenedataDssServer.java
deleted file mode 100644
index c9b0fa5ccff..00000000000
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/IGenedataDssServer.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.shared.api;
-
-import java.util.List;
-
-import org.springframework.transaction.annotation.Transactional;
-
-import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.AuthorizationGuard;
-import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.RoleSet;
-import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.RolesAllowed;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.authorization.ScreenerDatasetPredicate;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.authorization.ScreenerWellPredicate;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDataset;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IDatasetIdentifier;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetMetadata;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateSingleImage;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.WellFeaturesReference;
-
-/**
- * @author Tomasz Pylak
- */
-public interface IGenedataDssServer
-{
-    /**
-     * For a given set of feature vector data sets provide the list of all available features. This
-     * is just the name of the feature. If for different data sets different sets of features are
-     * available, provide the union of the features of all data sets.
-     */
-    @Transactional(readOnly = true)
-    @RolesAllowed(RoleSet.OBSERVER)
-    List<String> listAvailableFeatureNames(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = ScreenerDatasetPredicate.class) List<IDatasetIdentifier> featureDatasets);
-
-    /**
-     * For a given set of data sets and a set of features (given by their name), provide the feature
-     * matrix. Each column in that matrix is one feature, each row is one well in one data set.
-     */
-    @Transactional(readOnly = true)
-    @RolesAllowed(RoleSet.OBSERVER)
-    List<FeatureVectorDataset> loadFeatures(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = ScreenerDatasetPredicate.class) List<IDatasetIdentifier> featureDatasets,
-            List<String> featureNames);
-
-    /**
-     * For a given set of wells (given by data set code / well position), provide all images for all
-     * channels and tiles. To be more precise: find the image parent data set for each feature
-     * vector data set given by data set code and then provide the images for a sub set of the wells
-     * of this image data set. Do this for all feature vector data sets.
-     */
-    @Transactional(readOnly = true)
-    @RolesAllowed(RoleSet.OBSERVER)
-    List<PlateSingleImage> loadWellImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = ScreenerWellPredicate.class) List<WellFeaturesReference> wells);
-
-    /**
-     * For a given set of image data sets, provide all image channels that have been acquired and
-     * the available (natural) image size(s).
-     */
-    @Transactional(readOnly = true)
-    @RolesAllowed(RoleSet.OBSERVER)
-    List<ImageDatasetMetadata> listImageMetadata(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = ScreenerDatasetPredicate.class) List<IDatasetIdentifier> imageDatasets);
-
-}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/IScreeningApiServer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/IScreeningApiServer.java
index e744e3186f3..ecc24d346d0 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/IScreeningApiServer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/IScreeningApiServer.java
@@ -24,11 +24,14 @@ import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.Authoriz
 import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.ReturnValueFilter;
 import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.RoleSet;
 import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.DataSetCodePredicate;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.authorization.ScreenerPlateValidator;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.authorization.ScreenerReadonlyPlatePredicate;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Dataset;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IPlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.FeatureVectorDatasetReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.ImageDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Plate;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateIdentifier;
 
 /**
  * This interface is a part of the official public screening API. It is forbidden to change it in a
@@ -67,9 +70,9 @@ public interface IScreeningApiServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleSet.OBSERVER)
-    List<Dataset> listFeatureVectorDatasets(
+    List<FeatureVectorDatasetReference> listFeatureVectorDatasets(
             String sessionToken,
-            @AuthorizationGuard(guardClass = ScreenerReadonlyPlatePredicate.class) List<? extends IPlateIdentifier> plates)
+            @AuthorizationGuard(guardClass = ScreenerReadonlyPlatePredicate.class) List<? extends PlateIdentifier> plates)
             throws IllegalArgumentException;
 
     /**
@@ -78,8 +81,16 @@ public interface IScreeningApiServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleSet.OBSERVER)
-    List<Dataset> listImageDatasets(
+    List<ImageDatasetReference> listImageDatasets(
             String sessionToken,
-            @AuthorizationGuard(guardClass = ScreenerReadonlyPlatePredicate.class) List<? extends IPlateIdentifier> plates)
+            @AuthorizationGuard(guardClass = ScreenerReadonlyPlatePredicate.class) List<? extends PlateIdentifier> plates)
             throws IllegalArgumentException;
+
+    /**
+     * Converts a given list of dataset codes to dataset identifiers.
+     */
+    @Transactional(readOnly = true)
+    @RolesAllowed(RoleSet.OBSERVER)
+    List<IDatasetIdentifier> getDatasetIdentifiers(String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> datasetCodes);
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerDatasetPredicate.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerDatasetPredicate.java
deleted file mode 100644
index 95be78bcf54..00000000000
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerDatasetPredicate.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.shared.api.authorization;
-
-import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.DataSetCodePredicate;
-import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.DelegatedPredicate;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Dataset;
-
-/**
- * @author Tomasz Pylak
- */
-public class ScreenerDatasetPredicate extends DelegatedPredicate<String, Dataset>
-{
-    public ScreenerDatasetPredicate()
-    {
-        super(new DataSetCodePredicate());
-    }
-
-    @Override
-    public String convert(Dataset value)
-    {
-        return value.getDatasetCode();
-    }
-
-    @Override
-    public String getCandidateDescription()
-    {
-        return "dataset";
-    }
-}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerReadonlyPlatePredicate.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerReadonlyPlatePredicate.java
index c7597dd532e..7505500d63e 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerReadonlyPlatePredicate.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerReadonlyPlatePredicate.java
@@ -21,13 +21,13 @@ import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.SampleOwn
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IPlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateIdentifier;
 
 /**
  * @author Tomasz Pylak
  */
 public class ScreenerReadonlyPlatePredicate extends
-        DelegatedPredicate<SampleOwnerIdentifier, IPlateIdentifier>
+        DelegatedPredicate<SampleOwnerIdentifier, PlateIdentifier>
 {
 
     public ScreenerReadonlyPlatePredicate()
@@ -36,7 +36,7 @@ public class ScreenerReadonlyPlatePredicate extends
     }
 
     @Override
-    public SampleOwnerIdentifier convert(IPlateIdentifier value)
+    public SampleOwnerIdentifier convert(PlateIdentifier value)
     {
         return new SampleOwnerIdentifier(new SpaceIdentifier(DatabaseInstanceIdentifier
                 .createHome(), value.tryGetSpaceCode()));
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerWellPredicate.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerWellPredicate.java
deleted file mode 100644
index 390e87f2d4d..00000000000
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/authorization/ScreenerWellPredicate.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.shared.api.authorization;
-
-import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.DataSetCodePredicate;
-import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.DelegatedPredicate;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.WellFeaturesReference;
-
-/**
- * @author Tomasz Pylak
- */
-public class ScreenerWellPredicate extends DelegatedPredicate<String, WellFeaturesReference>
-{
-    public ScreenerWellPredicate()
-    {
-        super(new DataSetCodePredicate());
-    }
-
-    @Override
-    public String getCandidateDescription()
-    {
-        return "well";
-    }
-
-    @Override
-    public String convert(WellFeaturesReference value)
-    {
-        return value.getFeatureVectorDataset().getDatasetCode();
-    }
-}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/Dataset.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/Dataset.java
deleted file mode 100644
index c9acb66258f..00000000000
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/Dataset.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto;
-
-import java.io.Serializable;
-
-/**
- * Description of one dataset.
- * 
- * @author Tomasz Pylak
- */
-public class Dataset implements IDatasetIdentifier, Serializable
-{
-    private static final long serialVersionUID = 1L;
-
-    private final String datasetCode;
-
-    private final String datastoreCode;
-
-    private final IPlateIdentifier plate;
-
-    public Dataset(String datasetCode, String datastoreCode, IPlateIdentifier plate)
-    {
-        this.datasetCode = datasetCode;
-        this.datastoreCode = datastoreCode;
-        this.plate = plate;
-    }
-
-    /** a code of the dataset */
-    public String getDatasetCode()
-    {
-        return datasetCode;
-    }
-
-    /** a code which points to the datastore server on which the dataset is accessible */
-    public String getDatastoreCode()
-    {
-        return datastoreCode;
-    }
-
-    /** a pointer to a plate to which the dataset belongs */
-    public IPlateIdentifier getPlate()
-    {
-        return plate;
-    }
-
-    @Override
-    public String toString()
-    {
-        return datasetCode;
-    }
-}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/DatasetIdentifier.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/DatasetIdentifier.java
new file mode 100644
index 00000000000..3a666695f78
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/DatasetIdentifier.java
@@ -0,0 +1,58 @@
+package ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto;
+
+import java.io.Serializable;
+
+/**
+ * Contains data which uniquely define a dataset.
+ * 
+ * @author Tomasz Pylak
+ */
+public class DatasetIdentifier implements Serializable, IDatasetIdentifier
+{
+    private static final long serialVersionUID = 1L;
+
+    private final String datasetCode;
+
+    // a.k.a. downloadURL
+    private final String datastoreServerUrl;
+
+    public DatasetIdentifier(String datasetCode, String datastoreServerUrl)
+    {
+        this.datasetCode = datasetCode;
+        this.datastoreServerUrl = datastoreServerUrl;
+    }
+
+    /** a code of the dataset */
+    public String getDatasetCode()
+    {
+        return datasetCode;
+    }
+
+    public String getDatastoreServerUrl()
+    {
+        return datastoreServerUrl;
+    }
+
+    @Override
+    public String toString()
+    {
+        return datasetCode;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null || obj instanceof DatasetIdentifier == false)
+        {
+            return false;
+        }
+        DatasetIdentifier that = (DatasetIdentifier) obj;
+        return datasetCode.equals(that.datasetCode);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return datasetCode.hashCode();
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/DatasetReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/DatasetReference.java
new file mode 100644
index 00000000000..a46585ae7a7
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/DatasetReference.java
@@ -0,0 +1,33 @@
+package ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto;
+
+import java.io.Serializable;
+
+/**
+ * Description of one dataset.
+ * 
+ * @author Tomasz Pylak
+ */
+public class DatasetReference extends DatasetIdentifier implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    private final PlateIdentifier plate;
+
+    public DatasetReference(String datasetCode, String datastoreServerUrl, PlateIdentifier plate)
+    {
+        super(datasetCode, datastoreServerUrl);
+        this.plate = plate;
+    }
+
+    /** a pointer to a plate to which the dataset belongs */
+    public PlateIdentifier getPlate()
+    {
+        return plate;
+    }
+
+    @Override
+    public String toString()
+    {
+        return super.toString() + " (plate: " + plate + ")";
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/FeatureVectorDatasetReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/FeatureVectorDatasetReference.java
new file mode 100644
index 00000000000..ca950190a66
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/FeatureVectorDatasetReference.java
@@ -0,0 +1,34 @@
+/*
+ * 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.shared.api.dto;
+
+/**
+ * Description of one feature vector dataset.
+ * 
+ * @author Tomasz Pylak
+ */
+public class FeatureVectorDatasetReference extends DatasetReference implements
+        IFeatureVectorDatasetIdentifier
+{
+    private static final long serialVersionUID = 1L;
+
+    public FeatureVectorDatasetReference(String datasetCode, String datastoreServerUrl,
+            PlateIdentifier plate)
+    {
+        super(datasetCode, datastoreServerUrl, plate);
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IDatasetIdentifier.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IDatasetIdentifier.java
index 84b02780f0d..f6d5c2a908d 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IDatasetIdentifier.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IDatasetIdentifier.java
@@ -1,3 +1,19 @@
+/*
+ * 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.shared.api.dto;
 
 /**
@@ -8,8 +24,9 @@ package ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto;
 public interface IDatasetIdentifier
 {
     /** a code of the dataset */
-    String getDatasetCode();
+    public String getDatasetCode();
 
     /** a code which points to the datastore server on which the dataset is accessible */
-    String getDatastoreCode();
+    public String getDatastoreServerUrl();
+
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IFeatureVectorDatasetIdentifier.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IFeatureVectorDatasetIdentifier.java
new file mode 100644
index 00000000000..9747dce82ca
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IFeatureVectorDatasetIdentifier.java
@@ -0,0 +1,26 @@
+/*
+ * 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.shared.api.dto;
+
+/**
+ * Contains data which uniquely define a feature vector dataset.
+ * 
+ * @author Tomasz Pylak
+ */
+public interface IFeatureVectorDatasetIdentifier extends IDatasetIdentifier
+{
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IImageDatasetIdentifier.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IImageDatasetIdentifier.java
new file mode 100644
index 00000000000..093d1a4d70c
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IImageDatasetIdentifier.java
@@ -0,0 +1,26 @@
+/*
+ * 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.shared.api.dto;
+
+/**
+ * Contains data which uniquely define an image dataset.
+ * 
+ * @author Tomasz Pylak
+ */
+public interface IImageDatasetIdentifier extends IDatasetIdentifier
+{
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IPlateIdentifier.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IPlateIdentifier.java
deleted file mode 100644
index e398a4b80c8..00000000000
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/IPlateIdentifier.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto;
-
-/**
- * Contains data which uniquely define a plate
- * 
- * @author Tomasz Pylak
- */
-public interface IPlateIdentifier
-{
-    /** a code of the plate */
-    String getPlateCode();
-
-    /** a code of the space to which the plate belongs or null if it is a shared plate */
-    String tryGetSpaceCode();
-}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/ImageDatasetMetadata.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/ImageDatasetMetadata.java
index 8ee5750525d..b8e7d956f1c 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/ImageDatasetMetadata.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/ImageDatasetMetadata.java
@@ -15,15 +15,18 @@ public class ImageDatasetMetadata implements Serializable
 
     private final int channelsNumber;
 
+    private final int tilesNumber;
+
     private final int width;
 
     private final int height;
 
-    public ImageDatasetMetadata(IDatasetIdentifier dataset, int channelsNumber, int width,
-            int height)
+    public ImageDatasetMetadata(IDatasetIdentifier dataset, int channelsNumber, int tilesNumber,
+            int width, int height)
     {
         this.imageDataset = dataset;
         this.channelsNumber = channelsNumber;
+        this.tilesNumber = tilesNumber;
         this.width = width;
         this.height = height;
     }
@@ -42,6 +45,14 @@ public class ImageDatasetMetadata implements Serializable
         return channelsNumber;
     }
 
+    /**
+     * number of image tiles (aka fields) into which each well is splited
+     */
+    public int getTilesNumber()
+    {
+        return tilesNumber;
+    }
+
     /** width of all the images in the described dataset */
     public int getWidth()
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/ImageDatasetReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/ImageDatasetReference.java
new file mode 100644
index 00000000000..735ed66f9f4
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/ImageDatasetReference.java
@@ -0,0 +1,33 @@
+/*
+ * 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.shared.api.dto;
+
+/**
+ * Description of one image dataset.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ImageDatasetReference extends DatasetReference implements IImageDatasetIdentifier
+{
+    private static final long serialVersionUID = 1L;
+
+    public ImageDatasetReference(String datasetCode, String datastoreServerUrl,
+            PlateIdentifier plate)
+    {
+        super(datasetCode, datastoreServerUrl, plate);
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/Plate.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/Plate.java
index 1bc1bd22d71..ed8ff9e3ef3 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/Plate.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/Plate.java
@@ -7,24 +7,17 @@ import java.io.Serializable;
  * 
  * @author Tomasz Pylak
  */
-public class Plate implements IPlateIdentifier, Serializable
+public class Plate extends PlateIdentifier implements Serializable
 {
     private static final long serialVersionUID = 1L;
 
-    private String plateCode, experimentCode, projectCode, spaceCodeOrNull;
+    private String experimentCode, projectCode;
 
     public Plate(String plateCode, String experimentCode, String projectCode, String spaceCodeOrNull)
     {
-        this.plateCode = plateCode;
+        super(plateCode, spaceCodeOrNull);
         this.experimentCode = experimentCode;
         this.projectCode = projectCode;
-        this.spaceCodeOrNull = spaceCodeOrNull;
-    }
-
-    /** a code of the plate */
-    public String getPlateCode()
-    {
-        return plateCode;
     }
 
     /** a code of the experiment to which the plate belongs */
@@ -38,18 +31,4 @@ public class Plate implements IPlateIdentifier, Serializable
     {
         return projectCode;
     }
-
-    /** a code of the space to which the plate belongs or null if it is a shared plate */
-    public String tryGetSpaceCode()
-    {
-        return spaceCodeOrNull;
-    }
-
-    @Override
-    public String toString()
-    {
-        return (spaceCodeOrNull != null ? "/" + spaceCodeOrNull : "shared") + "/" + projectCode
-                + "/" + experimentCode + "/" + plateCode;
-    }
-
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateIdentifier.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateIdentifier.java
new file mode 100644
index 00000000000..9d82e988d31
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateIdentifier.java
@@ -0,0 +1,52 @@
+package ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto;
+
+import java.io.Serializable;
+
+/**
+ * Contains data which uniquely define a plate
+ * 
+ * @author Tomasz Pylak
+ */
+public class PlateIdentifier implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    private String plateCode, spaceCodeOrNull;
+
+    public PlateIdentifier(String plateCode, String spaceCodeOrNull)
+    {
+        this.plateCode = plateCode;
+        this.spaceCodeOrNull = spaceCodeOrNull;
+    }
+
+    /** a code of the plate */
+    public String getPlateCode()
+    {
+        return plateCode;
+    }
+
+    /** a code of the space to which the plate belongs or null if it is a shared plate */
+    public String tryGetSpaceCode()
+    {
+        return spaceCodeOrNull;
+    }
+
+    @Override
+    public String toString()
+    {
+        return (spaceCodeOrNull != null ? "/" + spaceCodeOrNull : "") + "/" + plateCode;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null || obj instanceof Plate == false)
+        {
+            return false;
+        }
+        Plate that = (Plate) obj;
+        return plateCode.equals(that.getPlateCode())
+                && ((spaceCodeOrNull != null && spaceCodeOrNull.equals(that.tryGetSpaceCode())) || (spaceCodeOrNull == null && that
+                        .tryGetSpaceCode() == null));
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateImageReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateImageReference.java
new file mode 100644
index 00000000000..c817c0f35e3
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateImageReference.java
@@ -0,0 +1,53 @@
+package ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto;
+
+import java.io.Serializable;
+
+/**
+ * Identifies one well in a dataset containing images.
+ * 
+ * @author Tomasz Pylak
+ */
+public class PlateImageReference extends DatasetIdentifier implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    private final WellPosition wellPosition;
+
+    private final int tile;
+
+    private final int channel;
+
+    public PlateImageReference(int wellRow, int wellColumn, int tile, int channel,
+            IDatasetIdentifier dataset)
+    {
+        super(dataset.getDatasetCode(), dataset.getDatastoreServerUrl());
+        this.wellPosition = new WellPosition(wellRow, wellColumn);
+        this.tile = tile;
+        this.channel = channel;
+    }
+
+    /** well position on the plate */
+    public WellPosition getWellPosition()
+    {
+        return wellPosition;
+    }
+
+    /** a sequential number of an image tile, starts from 1 */
+    public int getTile()
+    {
+        return tile;
+    }
+
+    /** index of a channel in which an image has been taken, starts from 1 */
+    public int getChannel()
+    {
+        return channel;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Image for [dataset " + getDatasetCode() + ", well " + wellPosition + ", channel "
+                + channel + ", tile " + tile + "]";
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateSingleImage.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateSingleImage.java
index 08ac539a85d..e42e73bbd5f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateSingleImage.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/PlateSingleImage.java
@@ -13,41 +13,35 @@ public class PlateSingleImage implements Serializable
 {
     private static final long serialVersionUID = 1L;
 
-    private final WellPosition wellPosition;
-
-    private final int tile;
-
-    private final int channel;
+    private final PlateImageReference imageReference;
 
     private final InputStream image;
 
-    public PlateSingleImage(WellPosition wellPosition, int tile, int channel, InputStream image)
+    public PlateSingleImage(PlateImageReference imageReference, InputStream image)
     {
-        this.wellPosition = wellPosition;
-        this.tile = tile;
-        this.channel = channel;
+        this.imageReference = imageReference;
         this.image = image;
     }
 
     /** position of the well to which the image belongs */
     public WellPosition getWellPosition()
     {
-        return wellPosition;
+        return imageReference.getWellPosition();
     }
 
     /**
-     * tile (a.k.a. field) number. Each well can be separated into many tiles, for each tile one
-     * image is acquired.
+     * tile (aka field) number, each well can be separated into many tiles, for each tile one image
+     * is acquired.
      */
     public int getTile()
     {
-        return tile;
+        return imageReference.getTile();
     }
 
     /** Index of the channel. Starts from 1. */
     public int getChannel()
     {
-        return channel;
+        return imageReference.getChannel();
     }
 
     /** stream with a png image */
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/WellFeaturesReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/WellFeaturesReference.java
deleted file mode 100644
index c00df8e4b4a..00000000000
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/WellFeaturesReference.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto;
-
-import java.io.Serializable;
-
-/**
- * Identifies one well in a dataset containing feature vectors.
- * 
- * @author Tomasz Pylak
- */
-public class WellFeaturesReference implements Serializable
-{
-    private static final long serialVersionUID = 1L;
-
-    private final WellPosition wellPosition;
-
-    private final IDatasetIdentifier featureVectorDataset;
-
-    public WellFeaturesReference(WellPosition wellPosition, IDatasetIdentifier featureVectorDataset)
-    {
-        this.wellPosition = wellPosition;
-        this.featureVectorDataset = featureVectorDataset;
-    }
-
-    /** well position on the plate */
-    public WellPosition getWellPosition()
-    {
-        return wellPosition;
-    }
-
-    /** identifier of the dataset containing feature vectors */
-    public IDatasetIdentifier getFeatureVectorDataset()
-    {
-        return featureVectorDataset;
-    }
-}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/WellPosition.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/WellPosition.java
index be7f8a3d756..79472517672 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/WellPosition.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/dto/WellPosition.java
@@ -30,4 +30,10 @@ public class WellPosition implements Serializable
     {
         return wellColumn;
     }
+
+    @Override
+    public String toString()
+    {
+        return "[" + wellRow + ", " + wellColumn + "]";
+    }
 }
\ No newline at end of file
diff --git a/screening/source/java/screening-dssApplicationContext.xml b/screening/source/java/screening-dssApplicationContext.xml
new file mode 100644
index 00000000000..1342c06b707
--- /dev/null
+++ b/screening/source/java/screening-dssApplicationContext.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:tx="http://www.springframework.org/schema/tx"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans
+			http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+			http://www.springframework.org/schema/tx
+			http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
+      
+    <!--
+        // Replaces ${...} with corresponding values found in 'location' property. A value
+        // can be overridden by setting a corresponding system property.
+    -->
+    <bean id="propertyConfigurer"
+        class="ch.systemsx.cisd.common.spring.ExposablePropertyPaceholderConfigurer">
+        <property name="location" value="file:etc/service.properties" />
+        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
+        <property name="ignoreUnresolvablePlaceholders" value="true" />
+    </bean>
+    
+    <!-- 
+        // Screening specific configuration
+    -->
+    
+    <bean id="data-store-rpc-service-screening"
+        class="com.marathon.util.spring.StreamSupportingHttpInvokerServiceExporter">
+        <property name="service">
+            <bean class="ch.systemsx.cisd.openbis.dss.screening.server.DssServiceRpcScreening" >
+               <constructor-arg value="${storeroot-dir}" />
+            </bean>
+        </property>
+        <property name="serviceInterface" value="ch.systemsx.cisd.openbis.dss.screening.shared.api.IDssServiceRpcScreening" />
+    </bean>
+        
+    
+</beans>
\ No newline at end of file
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/ScreeningClientApiTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/ScreeningClientApiTest.java
index e22b5c6f174..2e3a6217b8d 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/ScreeningClientApiTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/ScreeningClientApiTest.java
@@ -16,30 +16,96 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
+import org.apache.log4j.lf5.util.StreamUtils;
+
 import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.Plate;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.IDatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateImageReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.PlateSingleImage;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.dto.WellPosition;
 
 /**
  * @author Tomasz Pylak
  */
 public class ScreeningClientApiTest
 {
-    private static final String USER_ID = "tpylak";
+    private static final String USER_ID = "a";
 
     private static final String USER_PASSWORD = "x";
 
-    private static final String SERVER_URL = "http://localhost:8888/openbis";
+    private static final String OPENBIS_SERVER_URL = "http://localhost:8888/openbis";
 
-    public static void main(String[] args)
+    public static void main(String[] args) throws IOException
     {
         ScreeningOpenbisServiceFacade facade =
-                ScreeningOpenbisServiceFacade.tryCreate(USER_ID, USER_PASSWORD, SERVER_URL);
-        List<Plate> plates = facade.listPlates();
-        System.out.println("Plates: " + plates);
-        System.out.println("Image datasets: " + facade.listImageDatasets(plates));
-        System.out.println("Feature vector datasets: " + facade.listFeatureVectorDatasets(plates));
+                ScreeningOpenbisServiceFacade.tryCreate(USER_ID, USER_PASSWORD, OPENBIS_SERVER_URL);
+        // List<Plate> plates = facade.listPlates();
+        // System.out.println("Plates: " + plates);
+        // List<ImageDatasetReference> imageDatasets = facade.listImageDatasets(plates);
+        // System.out.println("Image datasets: " + imageDatasets);
+        // List<FeatureVectorDatasetReference> featureVectorDatasets =
+        // facade.listFeatureVectorDatasets(plates);
+        // System.out.println("Feature vector datasets: " + featureVectorDatasets);
+
+        // test for feature vector dataset
+        // String datasetCode = "20091214153212961-474922"; // feature vector
+        String datasetCode = "20091216162628729-475111"; // image
+        IDatasetIdentifier datasetIdentifier = getDatasetIdentifier(facade, datasetCode);
+        loadImages(facade, datasetIdentifier);
+
+        facade.logout();
+    }
 
+    private static IDatasetIdentifier getDatasetIdentifier(ScreeningOpenbisServiceFacade facade,
+            String datasetCode)
+    {
+        IDatasetIdentifier datasetIdentifier =
+                facade.getDatasetIdentifiers(Arrays.asList(datasetCode)).get(0);
+        return datasetIdentifier;
+    }
+
+    private static void loadImages(ScreeningOpenbisServiceFacade facade,
+            IDatasetIdentifier datasetIdentifier) throws FileNotFoundException, IOException
+    {
+        for (int channel = 1; channel <= 2; channel++)
+        {
+            for (int tile = 4; tile <= 6; tile++)
+            {
+                List<PlateImageReference> imageRefs = new ArrayList<PlateImageReference>();
+                imageRefs.add(new PlateImageReference(1, 3, tile, channel, datasetIdentifier));
+                List<PlateSingleImage> images = facade.loadImages(imageRefs);
+                saveImages(images);
+            }
+        }
+
+    }
+
+    private static void saveImages(List<PlateSingleImage> images) throws FileNotFoundException,
+            IOException
+    {
+        for (PlateSingleImage image : images)
+        {
+            FileOutputStream out = new FileOutputStream(new File(createImageFileName(image)));
+            InputStream in = image.getImage();
+            StreamUtils.copyThenClose(in, out);
+            out.close();
+            in.close();
+        }
+    }
+
+    private static String createImageFileName(PlateSingleImage image)
+    {
+        WellPosition well = image.getWellPosition();
+        return "img_r" + well.getWellRow() + "_c" + well.getWellColumn() + "_ch"
+                + image.getChannel() + "_t" + image.getTile() + ".png";
     }
 }
-- 
GitLab