From 68ea66775f0dd2f11a90d3869b809d5046199e90 Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Mon, 24 Oct 2011 08:17:46 +0000
Subject: [PATCH] add: method
 IScreeningOpenbisServiceFacade.listAvailableFeatures() (merged from S117.x)

SVN: 23390
---
 .../server/DssServiceRpcScreening.java        |  23 ++-
 .../server/DssServiceRpcScreeningLogger.java  |   9 ++
 .../api/v1/IDssServiceRpcScreening.java       | 141 +++++++++---------
 .../v1/IScreeningOpenbisServiceFacade.java    |  11 ++
 .../api/v1/ScreeningOpenbisServiceFacade.java |  53 ++++++-
 .../shared/api/v1/dto/FeatureInformation.java | 120 +++++++++++++++
 .../server/DssServiceRpcScreeningTest.java    |  67 +++++++++
 .../v1/ScreeningOpenbisServiceFacadeTest.java |  49 +++++-
 8 files changed, 389 insertions(+), 84 deletions(-)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/FeatureInformation.java

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
index d24ee67ff7b..206f9cb668f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
@@ -61,6 +61,7 @@ import ch.systemsx.cisd.openbis.dss.shared.DssScreeningUtils;
 import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureInformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVector;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference;
@@ -105,7 +106,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc<IDssServiceRpc
     /**
      * The minor version of this service.
      */
-    public static final int MINOR_VERSION = 8;
+    public static final int MINOR_VERSION = 9;
 
     // this dao will hold one connection to the database
     private IImagingReadonlyQueryDAO dao;
@@ -178,6 +179,26 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc<IDssServiceRpc
         return result;
     }
 
+    public List<FeatureInformation> listAvailableFeatures(String sessionToken,
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets)
+    {
+        List<ImgFeatureDefDTO> featureDefinitions = getFeatureDefinitions(featureDatasets);
+
+        // add only new feature names
+        List<FeatureInformation> result = new ArrayList<FeatureInformation>(); // keep the order
+        for (ImgFeatureDefDTO featureDefinition : featureDefinitions)
+        {
+            FeatureInformation description =
+                    new FeatureInformation(featureDefinition.getCode(),
+                            featureDefinition.getLabel(), featureDefinition.getDescription());
+            if (result.contains(description) == false)
+            {
+                result.add(description);
+            }
+        }
+        return result;
+    }
+
     public List<ImageDatasetMetadata> listImageMetadata(String sessionToken,
             List<? extends IImageDatasetIdentifier> imageDatasets)
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningLogger.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningLogger.java
index c8f8b6ac31f..7706b1231a9 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningLogger.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningLogger.java
@@ -24,6 +24,7 @@ import ch.systemsx.cisd.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.dss.screening.shared.api.v1.IDssServiceRpcScreening;
 import ch.systemsx.cisd.openbis.dss.screening.shared.api.v1.LoadImageConfiguration;
 import ch.systemsx.cisd.openbis.generic.shared.AbstractServerLogger;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureInformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetWellReference;
@@ -75,6 +76,14 @@ public class DssServiceRpcScreeningLogger extends AbstractServerLogger implement
         return null;
     }
 
+    public List<FeatureInformation> listAvailableFeatures(String sessionToken,
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets)
+    {
+        logAccess(sessionToken, "load_available_features", "DATASET_REFERENCES(%s)",
+                featureDatasets);
+        return null;
+    }
+
     public List<FeatureVectorDataset> loadFeatures(String sessionToken,
             List<FeatureVectorDatasetReference> featureDatasets, List<String> featureCodes)
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
index 40fd5f08e7e..b5d3805d382 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
@@ -27,6 +27,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.Da
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.PrivilegeLevel;
 import ch.systemsx.cisd.openbis.dss.screening.shared.api.internal.authorization.DatasetIdentifierPredicate;
 import ch.systemsx.cisd.openbis.dss.screening.shared.api.internal.authorization.SingleDataSetIdentifierPredicate;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureInformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetWellReference;
@@ -66,9 +67,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @Deprecated
     @DataSetAccessGuard
-    public List<String> listAvailableFeatureNames(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<? extends IFeatureVectorDatasetIdentifier> featureDatasets);
+    public List<String> listAvailableFeatureNames(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets);
 
     /**
      * For a given set of feature vector data sets provide the list of all available features. This
@@ -77,9 +78,20 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(2)
     @DataSetAccessGuard
-    public List<String> listAvailableFeatureCodes(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<? extends IFeatureVectorDatasetIdentifier> featureDatasets);
+    public List<String> listAvailableFeatureCodes(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets);
+
+    /**
+     * For a given set of feature vector data sets provide the list of all available features. This
+     * contains the code, label and description of the feature. If for different data sets different
+     * sets of features are available, provide the union of the features of all data sets.
+     */
+    @MinimalMinorVersion(9)
+    @DataSetAccessGuard
+    public List<FeatureInformation> listAvailableFeatures(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets);
 
     /**
      * Conceptually, for a given list of data well references (i.e. specified wells on specified
@@ -93,10 +105,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      *         <var>featureDatasets</var>.
      */
     @DataSetAccessGuard
-    public List<FeatureVectorDataset> loadFeatures(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<FeatureVectorDatasetReference> featureDatasets,
-            List<String> featureCodes);
+    public List<FeatureVectorDataset> loadFeatures(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<FeatureVectorDatasetReference> featureDatasets, List<String> featureCodes);
 
     /**
      * Conceptually, for a given list of dataset well references (i.e. specified wells on specified
@@ -117,9 +128,8 @@ public interface IDssServiceRpcScreening extends IRpcService
     @MinimalMinorVersion(1)
     @DataSetAccessGuard
     public List<FeatureVectorWithDescription> loadFeaturesForDatasetWellReferences(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<FeatureVectorDatasetWellReference> datasetWellReferences,
-            List<String> featureCodes);
+            String sessionToken, @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<FeatureVectorDatasetWellReference> datasetWellReferences, List<String> featureCodes);
 
     /**
      * Provide images for a given list of image references (specified by data set code, well
@@ -134,10 +144,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(3)
     @DataSetAccessGuard
-    public InputStream loadImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<PlateImageReference> imageReferences,
-            boolean convertToPng);
+    public InputStream loadImages(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<PlateImageReference> imageReferences, boolean convertToPng);
 
     /**
      * Provide thumbnail images for a given list of image references (specified by data set code,
@@ -153,9 +162,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(6)
     @DataSetAccessGuard
-    public InputStream loadThumbnailImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<PlateImageReference> imageReferences);
+    public InputStream loadThumbnailImages(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<PlateImageReference> imageReferences);
 
     /**
      * Provide images (PNG encoded) for a given list of image references (given by data set code,
@@ -170,10 +179,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(4)
     @DataSetAccessGuard
-    public InputStream loadImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<PlateImageReference> imageReferences,
-            ImageSize size);
+    public InputStream loadImages(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<PlateImageReference> imageReferences, ImageSize size);
 
     /**
      * Provide images for a given list of image references (given by data set code, well position,
@@ -184,9 +192,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      * will be converted to PNG format before being shipped.
      */
     @DataSetAccessGuard
-    public InputStream loadImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<PlateImageReference> imageReferences);
+    public InputStream loadImages(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<PlateImageReference> imageReferences);
 
     /**
      * Provide images for specified data set, list of well positions, channel, and optional thumb
@@ -204,10 +212,10 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(4)
     @DataSetAccessGuard
-    public InputStream loadImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
-            List<WellPosition> wellPositions, String channel, ImageSize thumbnailSizeOrNull);
+    public InputStream loadImages(String sessionToken,
+            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class)
+            IDatasetIdentifier dataSetIdentifier, List<WellPosition> wellPositions, String channel,
+            ImageSize thumbnailSizeOrNull);
 
     /**
      * Provide images for specified microscopy data set, channel and optional thumb nail size.
@@ -228,10 +236,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(5)
     @DataSetAccessGuard
-    public InputStream loadImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
-            String channel, ImageSize thumbnailSizeOrNull);
+    public InputStream loadImages(String sessionToken,
+            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class)
+            IDatasetIdentifier dataSetIdentifier, String channel, ImageSize thumbnailSizeOrNull);
 
     /**
      * Provide images for a given list of image references (specified by data set code, well
@@ -249,10 +256,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(8)
     @DataSetAccessGuard
-    public InputStream loadImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<PlateImageReference> imageReferences,
-            LoadImageConfiguration configuration);
+    public InputStream loadImages(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<PlateImageReference> imageReferences, LoadImageConfiguration configuration);
 
     /**
      * Provide thumbnail images for specified microscopy data set. If no thumbnails are stored on
@@ -271,10 +277,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(6)
     @DataSetAccessGuard
-    public InputStream loadThumbnailImages(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
-            List<String> channels);
+    public InputStream loadThumbnailImages(String sessionToken,
+            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class)
+            IDatasetIdentifier dataSetIdentifier, List<String> channels);
 
     /**
      * Lists plate image references for specified data set, list of well positions and channel.
@@ -283,10 +288,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(4)
     @DataSetAccessGuard
-    public List<PlateImageReference> listPlateImageReferences(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
-            List<WellPosition> wellPositions, String channel);
+    public List<PlateImageReference> listPlateImageReferences(String sessionToken,
+            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class)
+            IDatasetIdentifier dataSetIdentifier, List<WellPosition> wellPositions, String channel);
 
     /**
      * Lists plate image references for specified data set, list of well positions and channels.
@@ -295,10 +299,10 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(6)
     @DataSetAccessGuard
-    public List<PlateImageReference> listPlateImageReferences(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
-            List<WellPosition> wellPositions, List<String> channels);
+    public List<PlateImageReference> listPlateImageReferences(String sessionToken,
+            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class)
+            IDatasetIdentifier dataSetIdentifier, List<WellPosition> wellPositions,
+            List<String> channels);
 
     /**
      * Lists microscopy image references for specified data set and channel.
@@ -307,10 +311,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(5)
     @DataSetAccessGuard
-    public List<MicroscopyImageReference> listImageReferences(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
-            String channel);
+    public List<MicroscopyImageReference> listImageReferences(String sessionToken,
+            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class)
+            IDatasetIdentifier dataSetIdentifier, String channel);
 
     /**
      * Lists microscopy image references for specified data set and channels.
@@ -319,10 +322,9 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(6)
     @DataSetAccessGuard
-    public List<MicroscopyImageReference> listImageReferences(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
-            List<String> channels);
+    public List<MicroscopyImageReference> listImageReferences(String sessionToken,
+            @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class)
+            IDatasetIdentifier dataSetIdentifier, List<String> channels);
 
     /**
      * Saves the specified transformer factory for the specified channel of the specified data. Note
@@ -332,10 +334,10 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(4)
     @DataSetAccessGuard(privilegeLevel = PrivilegeLevel.SPACE_POWER_USER)
-    public void saveImageTransformerFactory(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<IDatasetIdentifier> dataSetIdentifiers,
-            String channel, IImageTransformerFactory transformerFactory);
+    public void saveImageTransformerFactory(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<IDatasetIdentifier> dataSetIdentifiers, String channel,
+            IImageTransformerFactory transformerFactory);
 
     /**
      * Returns the transformer factory for the specified channel and the experiment to which the
@@ -346,18 +348,17 @@ public interface IDssServiceRpcScreening extends IRpcService
      */
     @MinimalMinorVersion(4)
     @DataSetAccessGuard
-    public IImageTransformerFactory getImageTransformerFactoryOrNull(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<IDatasetIdentifier> dataSetIdentifiers,
-            String channel);
+    public IImageTransformerFactory getImageTransformerFactoryOrNull(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<IDatasetIdentifier> dataSetIdentifiers, String channel);
 
     /**
      * For a given set of image data sets, provide all image channels that have been acquired and
      * the available (natural) image size(s).
      */
     @DataSetAccessGuard
-    public List<ImageDatasetMetadata> listImageMetadata(
-            String sessionToken,
-            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<? extends IImageDatasetIdentifier> imageDatasets);
+    public List<ImageDatasetMetadata> listImageMetadata(String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class)
+            List<? extends IImageDatasetIdentifier> imageDatasets);
 
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
index 919570c88b6..aba9faef4e7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
@@ -31,6 +31,7 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.filter.IDataSetFilter;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.filter.TypeBasedDataSetFilter;
 import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade.IImageOutputStreamProvider;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ExperimentIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureInformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetWellReference;
@@ -381,6 +382,16 @@ public interface IScreeningOpenbisServiceFacade
     public List<String> listAvailableFeatureCodes(
             List<? extends IFeatureVectorDatasetIdentifier> featureDatasets);
 
+    /**
+     * For a given set of feature vector data sets provide the list of all available features. This
+     * contains the code, label and description of the feature. If for different data sets different
+     * sets of features are available, provide the union of the features of all data sets.
+     * 
+     * Only available when all data store services have minor version 9 or newer.
+     */
+    public List<FeatureInformation> listAvailableFeatures(
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets);
+
     /**
      * For a given set of plates and a set of features (given by their code), provide all the
      * feature vectors.
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 534fba670f0..650d7911283 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
@@ -57,6 +57,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.WellImageCache.We
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.IScreeningApiServer;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.DatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ExperimentIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureInformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetWellReference;
@@ -640,7 +641,8 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
     public List<ch.systemsx.cisd.openbis.dss.client.api.v1.DataSet> getDataSetMetaData(
             List<String> dataSetCodes)
     {
-        List<DataSet> dataSets = generalInformationService.getDataSetMetaData(sessionToken, dataSetCodes);
+        List<DataSet> dataSets =
+                generalInformationService.getDataSetMetaData(sessionToken, dataSetCodes);
         final List<ch.systemsx.cisd.openbis.dss.client.api.v1.DataSet> result =
                 new ArrayList<ch.systemsx.cisd.openbis.dss.client.api.v1.DataSet>();
         for (DataSet dataSet : dataSets)
@@ -784,6 +786,45 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
         return new ArrayList<String>(result);
     }
 
+    /**
+     * For a given set of feature vector data sets provide the list of all available features. This
+     * contains the code, label and description of the feature. If for different data sets different
+     * sets of features are available, provide the union of the features of all data sets. Only
+     * available when all data store services have minor version 9 or newer.
+     */
+    public List<FeatureInformation> listAvailableFeatures(
+            List<? extends IFeatureVectorDatasetIdentifier> featureDatasets)
+    {
+        final Set<FeatureInformation> result = new HashSet<FeatureInformation>();
+        featureVectorDataSetIdentifierMultiplexer.process(featureDatasets,
+                new IReferenceHandler<IFeatureVectorDatasetIdentifier>()
+                    {
+                        public void handle(DssServiceRpcScreeningHolder dssService,
+                                List<IFeatureVectorDatasetIdentifier> references)
+                        {
+                            if (hasDSSMethod(dssService, "listAvailableFeatures", List.class))
+                            {
+                                result.addAll(dssService.getService().listAvailableFeatures(
+                                        sessionToken, references));
+                            } else
+                            {
+                                checkDSSMinimalMinorVersion(dssService,
+                                        "listAvailableFeatureNames", List.class);
+                                // Use old method in order to allow accessing older servers.
+                                @SuppressWarnings("deprecation")
+                                final List<String> codes =
+                                        dssService.getService().listAvailableFeatureNames(
+                                                sessionToken, references);
+                                for (String code : codes)
+                                {
+                                    result.add(new FeatureInformation(code, code, ""));
+                                }
+                            }
+                        }
+                    });
+        return new ArrayList<FeatureInformation>(result);
+    }
+
     /**
      * For a given set of plates and a set of features (given by their code), provide all the
      * feature vectors.
@@ -1164,8 +1205,8 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
     }
 
     public void loadImages(final List<PlateImageReference> imageReferences,
-            final boolean convertToPNG,
-            final IPlateImageHandler plateImageHandler) throws IOException
+            final boolean convertToPNG, final IPlateImageHandler plateImageHandler)
+            throws IOException
     {
         try
         {
@@ -1192,7 +1233,8 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
                                                     references);
                                 }
 
-                                processImagesStreamUnchecked(plateImageHandler, imageReferences, stream);
+                                processImagesStreamUnchecked(plateImageHandler, imageReferences,
+                                        stream);
                             }
                         });
         } catch (WrappedIOException ex)
@@ -1304,7 +1346,7 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
                             final InputStream stream =
                                     dssService.getService().loadImages(sessionToken, references,
                                             sizeOrNull);
-                            
+
                             processImagesStreamUnchecked(plateImageHandler, references, stream);
                         }
                     });
@@ -1714,6 +1756,7 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
                         }
                     });
     }
+
     private void processImagesStreamUnchecked(final IPlateImageHandler plateImageHandler,
             List<PlateImageReference> references, final InputStream stream)
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/FeatureInformation.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/FeatureInformation.java
new file mode 100644
index 00000000000..fd7776d09bc
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/FeatureInformation.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2011 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.v1.dto;
+
+import java.io.Serializable;
+
+/**
+ * A bean that provides information about a feature.
+ * 
+ * @since 1.9
+ * @author Bernd Rinn
+ */
+public class FeatureInformation implements Serializable, Comparable<FeatureInformation>
+{
+
+    private static final long serialVersionUID = 1L;
+
+    private final String code;
+
+    private final String label;
+
+    public FeatureInformation(String code, String label, String description)
+    {
+        super();
+        this.code = code;
+        this.label = label;
+        this.description = description;
+    }
+
+    private final String description;
+
+    /**
+     * Returns the code of the feature.
+     */
+    public String getCode()
+    {
+        return code;
+    }
+
+    /**
+     * Returns the label of the feature (pretty-print, but not guaranteed to be unique).
+     */
+    public String getLabel()
+    {
+        return label;
+    }
+
+    /**
+     * Returns the text description of the feature.
+     */
+    public String getDescription()
+    {
+        return description;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((code == null) ? 0 : code.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        FeatureInformation other = (FeatureInformation) obj;
+        if (code == null)
+        {
+            if (other.code != null)
+            {
+                return false;
+            }
+        } else if (code.equals(other.code) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public int compareTo(FeatureInformation o)
+    {
+        return code.compareTo(o.getCode());
+    }
+
+    @Override
+    public String toString()
+    {
+        return "FeatureDescription [code=" + code + ", label=" + label + ", description="
+                + description + "]";
+    }
+
+}
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
index 839e2474176..7efc6898933 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
@@ -74,6 +74,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.DatasetIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureInformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVector;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference;
@@ -281,6 +282,43 @@ public class DssServiceRpcScreeningTest extends AssertJUnit
         context.assertIsSatisfied();
     }
 
+    @Test
+    public void testListAvailableFeatures()
+    {
+        prepareAssetDataSetsAreAccessible();
+        prepareLockDataSet("ds1", "ds2");
+
+        long[] dataSetIDs = new long[]
+            { 1, 2 };
+        FeatureInformation[][] featureCodesPerDataset =
+                new FeatureInformation[][]
+                    {
+                                {
+                                        new FeatureInformation("f1", "Feature 1",
+                                                "The first feature."),
+                                        new FeatureInformation("f2", "Feature 2",
+                                                "The second feature.") },
+                                {
+                                        new FeatureInformation("f2", "Feature 2",
+                                                "The second feature."),
+                                        new FeatureInformation("f3", "Feature 3",
+                                                "The third feature.") } };
+        prepareListAnalysisDatasets(dataSetIDs);
+        prepareGetFeatureDefinitions(dataSetIDs, featureCodesPerDataset);
+
+        List<FeatureInformation> features =
+                screeningService.listAvailableFeatures(SESSION_TOKEN, Arrays.asList(
+                        featureVectorDatasetIdentifier1, featureVectorDatasetIdentifier2));
+
+        assertEquals(
+                "[FeatureDescription [code=F1, label=Feature 1, description=The first feature.], "
+                        + "FeatureDescription [code=F2, label=Feature 2, description=The second feature.], "
+                        + "FeatureDescription [code=F3, label=Feature 3, description=The third feature.]]",
+                features.toString());
+        assertTrue(testMethodInterceptor.methodInvoked);
+        context.assertIsSatisfied();
+    }
+
     @Test
     public void testLoadFeatures()
     {
@@ -758,6 +796,35 @@ public class DssServiceRpcScreeningTest extends AssertJUnit
             });
     }
 
+    private void prepareGetFeatureDefinitions(final long[] dataSetIDs,
+            final FeatureInformation[]... featursPerDataset)
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    List<ImgFeatureDefDTO> defs = new ArrayList<ImgFeatureDefDTO>();
+                    int datasetIx = 0;
+                    for (FeatureInformation[] featureCodes : featursPerDataset)
+                    {
+                        long dataSetID = dataSetIDs[datasetIx];
+                        for (FeatureInformation desc : featureCodes)
+                        {
+                            ImgFeatureDefDTO def =
+                                    new ImgFeatureDefDTO(desc.getLabel(), desc.getCode(), desc
+                                            .getDescription(), 0);
+                            def.setDataSetId(dataSetID);
+                            def.setId(getFeatureDefId(desc.getCode()));
+                            defs.add(def);
+                        }
+                        datasetIx++;
+                    }
+
+                    one(dao).listFeatureDefsByDataSetIds(dataSetIDs);
+                    will(returnValue(defs));
+                }
+            });
+    }
+
     private void prepareGetFeatureVocabularyTerms(final long[] dataSetIDs)
     {
         context.checking(new Expectations()
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacadeTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacadeTest.java
index ee4ca283a97..8632285244e 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacadeTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacadeTest.java
@@ -68,6 +68,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.server.ScreeningServer;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.IScreeningApiServer;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.DatasetIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ExperimentIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureInformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetWellReference;
@@ -242,6 +243,34 @@ public class ScreeningOpenbisServiceFacadeTest extends AbstractFileSystemTestCas
         context.assertIsSatisfied();
     }
 
+    @Test
+    public void testAvailableFeatures()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(dssService1).listAvailableFeatures(SESSION_TOKEN, Arrays.asList(f1id));
+                    will(returnValue(Arrays.asList(new FeatureInformation("f1", "Feature 1",
+                            "The first feature."), new FeatureInformation("f2", "Feature 2",
+                            "The second feature."))));
+
+                    one(dssService2).listAvailableFeatures(SESSION_TOKEN, Arrays.asList(f2id));
+                    will(returnValue(Arrays.asList(new FeatureInformation("f2", "Feature 2",
+                            "The second feature."), new FeatureInformation("f3", "Feature 3",
+                            "The third feature."))));
+                }
+            });
+        List<FeatureInformation> features = facade.listAvailableFeatures(Arrays.asList(f1id, f2id));
+        Collections.sort(features);
+
+        assertEquals(
+                "[FeatureDescription [code=f1, label=Feature 1, description=The first feature.], "
+                        + "FeatureDescription [code=f2, label=Feature 2, description=The second feature.], "
+                        + "FeatureDescription [code=f3, label=Feature 3, description=The third feature.]]",
+                features.toString());
+        context.assertIsSatisfied();
+    }
+
     @Test
     public void testListFeatureVectorDataSetsWithUnspecifiedAnalysisProcedure()
     {
@@ -718,8 +747,9 @@ public class ScreeningOpenbisServiceFacadeTest extends AbstractFileSystemTestCas
                 {
                     one(dssService1).loadImages(SESSION_TOKEN, Arrays.asList(r1), true);
                     ConcatenatedContentInputStream s1 =
-                            new ConcatenatedContentInputStream(true, Arrays
-                                    .<IHierarchicalContentNode> asList(new ByteArrayBasedContentNode(
+                            new ConcatenatedContentInputStream(
+                                    true,
+                                    Arrays.<IHierarchicalContentNode> asList(new ByteArrayBasedContentNode(
                                             "hello 1".getBytes(), "h1")));
                     will(returnValue(s1));
 
@@ -728,8 +758,9 @@ public class ScreeningOpenbisServiceFacadeTest extends AbstractFileSystemTestCas
 
                     one(dssService2).loadImages(SESSION_TOKEN, Arrays.asList(r2), true);
                     ConcatenatedContentInputStream s2 =
-                            new ConcatenatedContentInputStream(true, Arrays
-                                    .<IHierarchicalContentNode> asList(new ByteArrayBasedContentNode(
+                            new ConcatenatedContentInputStream(
+                                    true,
+                                    Arrays.<IHierarchicalContentNode> asList(new ByteArrayBasedContentNode(
                                             "hello 2".getBytes(), "h2")));
                     will(returnValue(s2));
 
@@ -760,15 +791,17 @@ public class ScreeningOpenbisServiceFacadeTest extends AbstractFileSystemTestCas
                 {
                     one(dssService1).loadImages(SESSION_TOKEN, Arrays.asList(r1), config);
                     ConcatenatedContentInputStream s1 =
-                            new ConcatenatedContentInputStream(true, Arrays
-                                    .<IHierarchicalContentNode> asList(new ByteArrayBasedContentNode(
+                            new ConcatenatedContentInputStream(
+                                    true,
+                                    Arrays.<IHierarchicalContentNode> asList(new ByteArrayBasedContentNode(
                                             "hello 1".getBytes(), "h1")));
                     will(returnValue(s1));
 
                     one(dssService2).loadImages(SESSION_TOKEN, Arrays.asList(r2), config);
                     ConcatenatedContentInputStream s2 =
-                            new ConcatenatedContentInputStream(true, Arrays
-                                    .<IHierarchicalContentNode> asList(new ByteArrayBasedContentNode(
+                            new ConcatenatedContentInputStream(
+                                    true,
+                                    Arrays.<IHierarchicalContentNode> asList(new ByteArrayBasedContentNode(
                                             "hello 2".getBytes(), "h2")));
                     will(returnValue(s2));
                 }
-- 
GitLab