diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java
index 2c5f832622b408a95a9cba711f6932b3f7699db0..9283687317ce1d06fa8968fa5ec3bfd21d6ec768 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java
@@ -21,7 +21,7 @@ import java.awt.image.BufferedImage;
 import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContentNode;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageTransfomationFactories;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.RequestedImageSize;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageFileExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageFileExtractor.java
index 09960e8adea6d243afddc3163f95d71d4e13ad53..50712b186241894e88b8ab73fbe9a06d2b604d8b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageFileExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageFileExtractor.java
@@ -41,9 +41,9 @@ import ch.systemsx.cisd.hcs.Geometry;
 import ch.systemsx.cisd.hcs.Location;
 import ch.systemsx.cisd.hcs.WellGeometry;
 import ch.systemsx.cisd.openbis.dss.etl.dto.RelativeImageFile;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailsInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ChannelDescription;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageStorageProcessor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageStorageProcessor.java
index 7abd34affdcecf6f077d4e97bcc7176f1539b26f..b80f9824cdf8c95993fa60fbc8c521828dba5660 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageStorageProcessor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageStorageProcessor.java
@@ -61,15 +61,15 @@ import ch.systemsx.cisd.openbis.dss.etl.PlateStorageProcessor.DatasetOwnerInform
 import ch.systemsx.cisd.openbis.dss.etl.PlateStorageProcessor.ImageDatasetOwnerInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageSeriesPoint;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageStorageConfiguraton;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.OriginalDataStorageFormat;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailsInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageStorageConfiguraton;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.OriginalDataStorageFormat;
-import ch.systemsx.cisd.openbis.dss.etl.jython.JythonPlateDataSetHandler;
+import ch.systemsx.cisd.openbis.dss.etl.jython.v1.JythonPlateDataSetHandler;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ChannelDescription;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ComputeIntensityLevelTransformationsMaintenanceTask.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ComputeIntensityLevelTransformationsMaintenanceTask.java
index 3c3081c18534f5c21d0b15bdeaa2fdfbc356e3fc..4fe390990c2e22621a21e1d304d95b446191badf 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ComputeIntensityLevelTransformationsMaintenanceTask.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ComputeIntensityLevelTransformationsMaintenanceTask.java
@@ -37,9 +37,9 @@ import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.maintenance.IMaintenanceTask;
 import ch.systemsx.cisd.common.properties.PropertyUtils;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformation;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformationBuffer;
-import ch.systemsx.cisd.openbis.dss.etl.jython.SimpleImageDataSetRegistrator;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformationBuffer;
+import ch.systemsx.cisd.openbis.dss.etl.jython.v1.SimpleImageDataSetRegistrator;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/FlexibleHCSImageFileExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/FlexibleHCSImageFileExtractor.java
index 5cf660cf96787875215162f16daf02ca4bbb4e6d..d8f88e347dec8efe55d9c25bfcf62b610898f2eb 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/FlexibleHCSImageFileExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/FlexibleHCSImageFileExtractor.java
@@ -20,7 +20,7 @@ import java.io.File;
 import java.util.Properties;
 
 import ch.systemsx.cisd.openbis.dss.etl.dto.UnparsedImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 
 /**
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageDatasetUploader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageDatasetUploader.java
index 354e20f36421390c04b760c73dbbf28a882c1ac8..2f31e612b754cdae096e2c1a38ba3bac8730b849 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageDatasetUploader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageDatasetUploader.java
@@ -24,7 +24,7 @@ import ch.systemsx.cisd.openbis.dss.etl.ImagingDatabaseHelper.ExperimentWithChan
 import ch.systemsx.cisd.openbis.dss.etl.ImagingDatabaseHelper.ImagingChannelsMap;
 import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageZoomLevel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgImageZoomLevelDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgSpotDTO;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageFileExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageFileExtractor.java
index dee8e2d5f3216df78c85b84e3779ff547b47cd15..f634e70062f72b9f0683539a1d43ed8d04598057 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageFileExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageFileExtractor.java
@@ -25,7 +25,7 @@ import org.apache.commons.lang.StringUtils;
 import ch.systemsx.cisd.common.properties.PropertyUtils;
 import ch.systemsx.cisd.hcs.Location;
 import ch.systemsx.cisd.openbis.dss.etl.dto.UnparsedImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
index 643d466d9ee1778ee1b321595df7e92e21f7fe0d..bf73bdf98911b3803120a5c39bddfc24629d0396 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
@@ -52,14 +52,14 @@ import ch.systemsx.cisd.common.process.ProcessIOStrategy;
 import ch.systemsx.cisd.common.process.ProcessResult;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.RelativeImageFile;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageStorageConfiguraton;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailsInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageStorageConfiguraton;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelsUtils;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImageFileExtractionResult.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImageFileExtractionResult.java
index d5a007aac581d25c1127509a1ada5efb3df0bf35..98bdf444582c2ce9e3190db2bc4c5468b166e862 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImageFileExtractionResult.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImageFileExtractionResult.java
@@ -20,7 +20,7 @@ import java.util.List;
 
 import ch.systemsx.cisd.hcs.Geometry;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
 
 /**
  * Class which contains the image extraction process results.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImageValidator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImageValidator.java
index 3c6c18cd58d4584c8825be5423c581c073e83e90..8b0c962cdd36f06589b36d5c138519a518d86cb7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImageValidator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImageValidator.java
@@ -29,7 +29,7 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.mail.IMailClient;
 import ch.systemsx.cisd.hcs.Geometry;
 import ch.systemsx.cisd.openbis.dss.etl.PlateStorageProcessor.DatasetOwnerInformation;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateDimension;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseHelper.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseHelper.java
index e73f63d36cbf7f3b92e2943bf6b911c0cd2a10fe..33773195aaa1ac229442455f0ee565c281859f7b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseHelper.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseHelper.java
@@ -26,10 +26,10 @@ import java.util.Set;
 import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColor;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgChannelDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgContainerDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgExperimentDTO;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyBlackboxSeriesStorageProcessor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyBlackboxSeriesStorageProcessor.java
index ad15383454023188425bca50306aef473e040a81..d8e619e90a566b5ffd1019b637af1535c491ab9d 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyBlackboxSeriesStorageProcessor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyBlackboxSeriesStorageProcessor.java
@@ -31,7 +31,7 @@ import ch.systemsx.cisd.openbis.dss.etl.PlateStorageProcessor.ImageDatasetOwnerI
 import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageDatasetInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ChannelDescription;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyImageDatasetUploader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyImageDatasetUploader.java
index 7f01908efa342bf6fbd37bd5fc2f164d85bce3a7..002725fe625f39ddca0444e63679bba523fd70e9 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyImageDatasetUploader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyImageDatasetUploader.java
@@ -22,7 +22,7 @@ import java.util.Map;
 import ch.systemsx.cisd.openbis.dss.etl.ImagingDatabaseHelper.ImagingChannelsMap;
 import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageZoomLevel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgImageZoomLevelDTO;
 
 /**
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyImageFileExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyImageFileExtractor.java
index a4814547e474ed364dc74f4e534a89cedef023e5..dd97875a9a549e2f782d9b8786b71ff079ad22c5 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyImageFileExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/MicroscopyImageFileExtractor.java
@@ -22,7 +22,7 @@ import java.util.Properties;
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 import ch.systemsx.cisd.hcs.Location;
 import ch.systemsx.cisd.openbis.dss.etl.dto.UnparsedImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateGeometryOracle.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateGeometryOracle.java
index 58c3415cf68fbbad650f0a93146d9e89ed92a291..11346c45b0e8439725b8b47720d02b6e5fd80d9f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateGeometryOracle.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateGeometryOracle.java
@@ -28,8 +28,8 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.shared.basic.string.StringUtils;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.hcs.Location;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedBasicOpenBISService;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTerm;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateStorageProcessor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateStorageProcessor.java
index 5364c9620b57a08d16a5c93f12ce2c9cf0e1f302..8229588f587c603b9dff3a6466612fb02ff6bb45 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateStorageProcessor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateStorageProcessor.java
@@ -31,10 +31,10 @@ import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageDatasetInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageZoomLevel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat.FileFormat;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailsInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat.FileFormat;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/TileGeometryOracle.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/TileGeometryOracle.java
index 5624c724a9089a1cf6ed5a86193c429905218f8a..c50bfe0f34b94ece1a07884466ed61ece70f32b9 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/TileGeometryOracle.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/TileGeometryOracle.java
@@ -25,7 +25,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 
 import ch.systemsx.cisd.common.geometry.SpatialPoint;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Location;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Location;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
 
 /**
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ImageMetadataExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ImageMetadataExtractor.java
index 1318e501f4231a74378454026a47cd33146297e8..49454ba304e7a158e24713757af001b4482e9c97 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ImageMetadataExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ImageMetadataExtractor.java
@@ -27,7 +27,7 @@ import ch.systemsx.cisd.imagereaders.ImageID;
 import ch.systemsx.cisd.imagereaders.ImageReaderConstants;
 import ch.systemsx.cisd.imagereaders.ImageReaderFactory;
 import ch.systemsx.cisd.openbis.dss.etl.TileGeometryOracle;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Location;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Location;
 
 /**
  * @author Kaloyan Enimanev
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingDatasetLoader.java
index 6f1103cf731f12d82d136cd1fc08a6164ca73575..794d196d34d785f36a4d8c13f539baa170bb1220 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingDatasetLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingDatasetLoader.java
@@ -35,7 +35,7 @@ import ch.systemsx.cisd.openbis.dss.etl.IImagingDatasetLoader;
 import ch.systemsx.cisd.openbis.dss.etl.PrefixedImage;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageTransfomationFactories;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageChannelStackReference;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageChannelStackReference.HCSChannelStackByLocationReference;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageChannelStackReference.MicroscopyChannelStackByLocationReference;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/RelativeImageFile.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/RelativeImageFile.java
index e05a871f502b5cb5abfe79d54633208c5f6e6652..f552f0ada8e39a13f7776199c5ae65447d8dd59e 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/RelativeImageFile.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/RelativeImageFile.java
@@ -19,7 +19,7 @@ package ch.systemsx.cisd.openbis.dss.etl.dto;
 import java.io.Serializable;
 
 import ch.systemsx.cisd.common.reflection.AbstractHashable;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 
 /**
  * Points to one image on the file system.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/UnparsedImageFileInfo.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/UnparsedImageFileInfo.java
index 6ae3e01cc00c44314681609fcb548b479d402967..38821a2c33a3430af8fae099b914323c0d953c35 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/UnparsedImageFileInfo.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/UnparsedImageFileInfo.java
@@ -1,7 +1,7 @@
 package ch.systemsx.cisd.openbis.dss.etl.dto;
 
 import ch.systemsx.cisd.common.reflection.AbstractHashable;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 
 /**
  * Intermediate DTO containing tokens from which image info {@link ImageFileInfo} can be extracted
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/BasicDataSetInformation.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/BasicDataSetInformation.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad1f671874787924345f39b9b14ad9851a7d14e1
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/BasicDataSetInformation.java
@@ -0,0 +1,89 @@
+/*
+ * 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.dss.etl.dto.api;
+
+import java.util.Arrays;
+
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+import ch.systemsx.cisd.openbis.generic.shared.IServer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
+
+/**
+ * Basic attributes of a dataset connected to a sample and optionally to one parent dataset.
+ * 
+ * @author Tomasz Pylak
+ */
+public class BasicDataSetInformation extends DataSetInformation
+{
+    private static final long serialVersionUID = IServer.VERSION;
+
+    private String fileFormatTypeCode;
+
+    // marks if a dataset is measured or derived from measured data
+    private boolean isMeasured = true;
+
+    /** Sets code of the dataset type */
+    public void setDatasetTypeCode(String datasetTypeCode)
+    {
+        DataSetType dataSetType = new DataSetType();
+        dataSetType.setCode(datasetTypeCode);
+        super.setDataSetType(dataSetType);
+    }
+
+    /** Mandatory: sets file format code. */
+    public void setFileFormatCode(String fileFormatCode)
+    {
+        this.fileFormatTypeCode = fileFormatCode;
+    }
+
+    /**
+     * Sets attributes of the connected sample - optional.
+     * <p>
+     * Alternatively, call
+     * {@link ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetUpdatable#setSample(ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.ISampleImmutable)}
+     * on the object returned by
+     * {@link ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetRegistrationTransaction#createNewDataSet()}.
+     */
+    public void setSample(String sampleSpaceCode, String sampleCode)
+    {
+        super.setSpaceCode(sampleSpaceCode);
+        super.setSampleCode(sampleCode);
+    }
+
+    /** attributes of the parent dataset - optional */
+    public void setParentDatasetCode(String parentDatasetCode)
+    {
+        super.setParentDataSetCodes(Arrays.asList(parentDatasetCode));
+    }
+
+    /** marks if a dataset is measured or derived from measured data */
+    public void setMeasured(boolean isMeasured)
+    {
+        this.isMeasured = isMeasured;
+    }
+
+    public String getFileFormatTypeCode()
+    {
+        return fileFormatTypeCode;
+    }
+
+    public boolean isMeasured()
+    {
+        return isMeasured;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/Channel.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/Channel.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a8465b4cffe1c7135338b0c4e7797fcadda8e25
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/Channel.java
@@ -0,0 +1,184 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
+
+import java.awt.Color;
+import java.io.Serializable;
+
+import ch.systemsx.cisd.common.image.WavelengthColor;
+import ch.systemsx.cisd.common.reflection.AbstractHashable;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation;
+
+/**
+ * A channel in which the image has been acquired.
+ * <p>
+ * Each channel has its <code>code</code> which uniquely identifies it in one experiment or dataset.
+ * </p>
+ * 
+ * @author Tomasz Pylak
+ */
+public class Channel extends AbstractHashable implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    private final String code;
+
+    private final String label;
+
+    private String description;
+
+    private Integer wavelength;
+
+    private ChannelColorRGB channelColorOrNull;
+
+    private ImageTransformation[] availableTransformations = new ImageTransformation[0];
+
+    /**
+     * Constructs a channel with a specified code and label. The channel will be presented in a
+     * default color.
+     */
+    public Channel(String code, String label)
+    {
+        this(code, label, (ChannelColorRGB) null);
+    }
+
+    /**
+     * Constructs a channel with a specified code and label. The channel will be presented in a
+     * specified color.
+     */
+    public Channel(String code, String label, ChannelColor channelColorOrNull)
+    {
+        this(code, label, convertColor(channelColorOrNull));
+    }
+
+    /**
+     * Version of method for v1 channel color to keep backwards compatibility
+     */
+    public Channel(String code, String label,
+            ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColor channelColorOrNull)
+    {
+        this(code, label, channelColorOrNull.getIndependentChannelColor());
+    }
+
+    /**
+     * Constructs a channel with a specified code and label. The channel will be presented in a
+     * specified color.
+     */
+    public Channel(String code, String label, ChannelColorRGB channelColorOrNull)
+    {
+        assert code != null : "code is null";
+        assert label != null : "label is null";
+        this.label = label;
+        this.code = code;
+        this.channelColorOrNull = channelColorOrNull;
+    }
+
+    private static ChannelColorRGB convertColor(ChannelColor plainChannelColorOrNull)
+    {
+        if (plainChannelColorOrNull == null)
+        {
+            return null;
+        }
+        return plainChannelColorOrNull.getRGB();
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public String tryGetDescription()
+    {
+        return description;
+    }
+
+    public Integer tryGetWavelength()
+    {
+        return wavelength;
+    }
+
+    public String getLabel()
+    {
+        return label;
+    }
+
+    /**
+     * @return color for the specified channel which will be used to display merged channels images.
+     *         null only during dataset registration when default color should be used, afterwards
+     *         never null.
+     */
+    public ChannelColorRGB tryGetChannelColor()
+    {
+        return channelColorOrNull;
+    }
+
+    // never null, can be empty
+    public ImageTransformation[] getAvailableTransformations()
+    {
+        return availableTransformations;
+    }
+
+    // ------------------- setters -------------------
+
+    /** Sets the description of the channel. Optional. */
+    public void setDescription(String description)
+    {
+        this.description = description;
+    }
+
+    /** Sets the wavelength of the light (in nanometers) used to acquire this channel. Optional. */
+    public void setWavelength(Integer wavelength)
+    {
+        this.wavelength = wavelength;
+    }
+
+    /**
+     * Sets the wavelength of the light (in nanometers) used to acquire this channel.<br>
+     * Additionally sets the channel color. The color is calculated for display on a computer
+     * monitor on the basis of the given wavelength using Bruton's algorithm. See <a
+     * href="http://www.midnightkite.com/color.html">COLOR SCIENCE web page</a> for details.
+     * <p>
+     * Optional.
+     */
+    public void setWavelengthAndColor(Integer wavelength)
+    {
+        this.wavelength = wavelength;
+        Color color = WavelengthColor.getColorForWavelength(wavelength);
+        setChannelColorRGB(convertColor(color));
+    }
+
+    private ChannelColorRGB convertColor(Color color)
+    {
+        return new ChannelColorRGB(color.getRed(), color.getGreen(), color.getBlue());
+    }
+
+    /** Sets the plain color in which this channel will be displayed. */
+    public void setChannelColor(ChannelColor channelColor)
+    {
+        this.channelColorOrNull = convertColor(channelColor);
+    }
+
+    /** version of method for v1 ChannelColor kept for backwards compatibility */
+    public void setChannelColor(
+            ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColor channelColor)
+    {
+        setChannelColor(channelColor.getIndependentChannelColor());
+    }
+
+    /** Sets RGB color in which this channel will be displayed. */
+    public void setChannelColorRGB(ChannelColorRGB channelColor)
+    {
+        this.channelColorOrNull = channelColor;
+    }
+
+    /** Sets available transformations which can be applied to images of this channel on request. */
+    public void setAvailableTransformations(ImageTransformation[] transformations)
+    {
+        if (transformations == null)
+        {
+            this.availableTransformations = new ImageTransformation[0];
+        } else
+        {
+            this.availableTransformations = transformations;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColor.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce01e320c95a9086a58130697c935834531f92f9
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColor.java
@@ -0,0 +1,71 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
+
+/**
+ * Allowed colors in which channels can be presented.
+ * 
+ * @author Tomasz Pylak
+ */
+public enum ChannelColor
+{
+    BLUE(0), GREEN(1), RED(2), RED_GREEN(3), RED_BLUE(4), GREEN_BLUE(5);
+
+    private static final int MAX_COLOR = calcMaxColorIndex();
+
+    // If no mapping between channels and colors has been provided then channels get consecutive
+    // colors. This field determines the order in which colors are assigned.
+    // It is important for backward compatibility as well.
+    private final int orderIndex;
+
+    private ChannelColor(int orderIndex)
+    {
+        this.orderIndex = orderIndex;
+    }
+
+    private static int calcMaxColorIndex()
+    {
+        int max = 0;
+        for (ChannelColor color : values())
+        {
+            max = Math.max(max, color.getColorOrderIndex());
+        }
+        return max;
+    }
+
+    public int getColorOrderIndex()
+    {
+        return orderIndex;
+    }
+
+    public static ChannelColor createFromIndex(int colorIndex)
+    {
+        for (ChannelColor color : values())
+        {
+            if (color.getColorOrderIndex() == colorIndex % (MAX_COLOR + 1))
+            {
+                return color;
+            }
+        }
+        throw new IllegalStateException("Invalid color index: " + colorIndex + "!");
+    }
+
+    public ChannelColorRGB getRGB()
+    {
+        switch (this)
+        {
+            case RED:
+                return new ChannelColorRGB(255, 0, 0);
+            case GREEN:
+                return new ChannelColorRGB(0, 255, 0);
+            case BLUE:
+                return new ChannelColorRGB(0, 0, 255);
+            case RED_GREEN:
+                return new ChannelColorRGB(255, 255, 0);
+            case GREEN_BLUE:
+                return new ChannelColorRGB(0, 255, 255);
+            case RED_BLUE:
+                return new ChannelColorRGB(255, 0, 255);
+            default:
+                throw new IllegalStateException("unhandled enum " + this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorComponent.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorComponent.java
new file mode 100644
index 0000000000000000000000000000000000000000..76b5b29952eb23e7df40c60916ee6b64498cc03c
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorComponent.java
@@ -0,0 +1,45 @@
+/*
+ * 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.dss.etl.dto.api;
+
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
+
+/**
+ * Color component of an image which constitutes one channel. Useful if the image consists of all
+ * channels merged together.
+ * 
+ * @author Tomasz Pylak
+ */
+public enum ChannelColorComponent
+{
+    RED, GREEN, BLUE;
+
+    public static ColorComponent getColorComponent(ChannelColorComponent channelColorComponent)
+    {
+        switch (channelColorComponent)
+        {
+            case BLUE:
+                return ColorComponent.BLUE;
+            case GREEN:
+                return ColorComponent.GREEN;
+            case RED:
+                return ColorComponent.RED;
+        }
+
+        return null;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorRGB.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorRGB.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b659e00d0e3f70ee62d296666e6cd75819ef799
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorRGB.java
@@ -0,0 +1,101 @@
+/*
+ * 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.dss.etl.dto.api;
+
+import java.io.Serializable;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ServiceVersionHolder;
+
+/**
+ * RGB color components specify the color in which channel should be displayed.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ChannelColorRGB implements Serializable
+{
+    private static final long serialVersionUID = ServiceVersionHolder.VERSION;
+
+    private int r, g, b;
+
+    @SuppressWarnings("unused")
+    private ChannelColorRGB()
+    {
+    }
+
+    public ChannelColorRGB(int r, int g, int b)
+    {
+        assert r >= 0 && r <= 255 : "invalid color " + r;
+        assert g >= 0 && g <= 255 : "invalid color " + g;
+        assert b >= 0 && b <= 255 : "invalid color " + b;
+
+        this.r = r;
+        this.g = g;
+        this.b = b;
+    }
+
+    public int getR()
+    {
+        return r;
+    }
+
+    public int getG()
+    {
+        return g;
+    }
+
+    public int getB()
+    {
+        return b;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Color(r=" + r + ", g=" + g + ", b=" + b + ")";
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + b;
+        result = prime * result + g;
+        result = prime * result + r;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ChannelColorRGB other = (ChannelColorRGB) obj;
+        if (b != other.b)
+            return false;
+        if (g != other.g)
+            return false;
+        if (r != other.r)
+            return false;
+        return true;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureDefinition.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IFeatureDefinition.java
similarity index 97%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureDefinition.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IFeatureDefinition.java
index 4d52a964e47d252dbd131b2a7d6cce1407640601..57e2813b7fd925e3590e353bbc2eb1fe0c5956bd 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureDefinition.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IFeatureDefinition.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
 
 /**
  * An interface which allows to define values of one feature.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeaturesBuilder.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IFeaturesBuilder.java
similarity index 94%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeaturesBuilder.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IFeaturesBuilder.java
index e44605f40ab11e71919992b9e2fd5dea7ab62de2..229259ebf3f93562629efa750f67e31be0c0c866 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeaturesBuilder.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IFeaturesBuilder.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
 
 /**
  * Allows to define feature vectors of one image analysis dataset.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageFileInfo.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageFileInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..d32a35aad31b517498a6a7f1cda20384903a90f5
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageFileInfo.java
@@ -0,0 +1,183 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
+
+import java.io.Serializable;
+
+import ch.systemsx.cisd.hcs.Location;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
+
+/**
+ * DTO with information about one image file
+ * 
+ * @author Tomasz Pylak
+ */
+public class ImageFileInfo implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    private WellLocation wellLocationOrNull;
+
+    private Location tileLocation;
+
+    private String channelCode;
+
+    private final String imageRelativePath;
+
+    private Float timepointOrNull;
+
+    private Float depthOrNull;
+
+    private Integer seriesNumberOrNull;
+
+    private ImageIdentifier imageIdentifier;
+
+    private String uniqueImageIdentifier;
+
+    private String containerDataSetCode;
+
+    public ImageFileInfo(String channelCode, int tileRow, int tileColumn, String imageRelativePath)
+    {
+        assert channelCode != null;
+        assert imageRelativePath != null;
+
+        this.channelCode = channelCode;
+        this.imageRelativePath = imageRelativePath;
+        setTile(tileRow, tileColumn);
+    }
+
+    public String tryGetUniqueStringIdentifier()
+    {
+        if (imageIdentifier != null)
+        {
+            return imageIdentifier.getUniqueStringIdentifier();
+        } else if (uniqueImageIdentifier != null)
+        {
+            return uniqueImageIdentifier;
+        }
+
+        return null;
+    }
+
+    public Integer tryGetWellRow()
+    {
+        return wellLocationOrNull == null ? null : wellLocationOrNull.getRow();
+    }
+
+    public Integer tryGetWellColumn()
+    {
+        return wellLocationOrNull == null ? null : wellLocationOrNull.getColumn();
+    }
+
+    public WellLocation tryGetWellLocation()
+    {
+        return wellLocationOrNull;
+    }
+
+    public boolean hasWellLocation()
+    {
+        return wellLocationOrNull != null;
+    }
+
+    public int getTileRow()
+    {
+        return tileLocation.getY();
+    }
+
+    public int getTileColumn()
+    {
+        return tileLocation.getX();
+    }
+
+    public String getChannelCode()
+    {
+        return channelCode;
+    }
+
+    public String getImageRelativePath()
+    {
+        return imageRelativePath;
+    }
+
+    public Float tryGetTimepoint()
+    {
+        return timepointOrNull;
+    }
+
+    public Float tryGetDepth()
+    {
+        return depthOrNull;
+    }
+
+    public Integer tryGetSeriesNumber()
+    {
+        return seriesNumberOrNull;
+    }
+
+    // --- setters
+
+    public void setImageIdentifier(ImageIdentifier imageIdentifier)
+    {
+        this.imageIdentifier = imageIdentifier;
+    }
+
+    public void setWell(int row, int column)
+    {
+        this.wellLocationOrNull = new WellLocation(row, column);
+    }
+
+    /** @return true if well row and column could be parsed */
+    public boolean setWell(String wellText)
+    {
+        try
+        {
+            this.wellLocationOrNull = WellLocation.parseLocationStr(wellText);
+        } catch (Exception e)
+        {
+            // do nothing
+        }
+        return wellLocationOrNull != null;
+    }
+
+    public void setTile(int row, int column)
+    {
+        this.tileLocation = Location.createLocationFromRowAndColumn(row, column);
+    }
+
+    public void setTimepoint(Float value)
+    {
+        this.timepointOrNull = value;
+    }
+
+    public void setDepth(Float value)
+    {
+        this.depthOrNull = value;
+    }
+
+    public void setSeriesNumber(Integer value)
+    {
+        this.seriesNumberOrNull = value;
+    }
+
+    public void setUniqueImageIdentifier(String uniqueImageIdentifier)
+    {
+        this.uniqueImageIdentifier = uniqueImageIdentifier;
+    }
+
+    public String getContainerDataSetCode()
+    {
+        return containerDataSetCode;
+    }
+
+    public void setContainerDataSetCode(String containerDataSetCode)
+    {
+        this.containerDataSetCode = containerDataSetCode;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "ImageFileInfo [well=" + wellLocationOrNull + ", tile=" + tileLocation
+                + ", channel=" + channelCode + ", path=" + imageRelativePath + ", timepoint="
+                + timepointOrNull + ", depth=" + depthOrNull + ", seriesNumber="
+                + seriesNumberOrNull + "]";
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageIdentifier.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageIdentifier.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5a71e6e446738f2864a41b5112634b16cb2c302
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageIdentifier.java
@@ -0,0 +1,135 @@
+/*
+ * 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.dss.etl.dto.api;
+
+import java.io.Serializable;
+
+import ch.systemsx.cisd.imagereaders.ImageID;
+
+/**
+ * Immutable value class of an image ID based on series index, time series index, focal plane index,
+ * and color channel index. It will be used to identify images in a container image file format like
+ * multi-page TIFF.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public class ImageIdentifier implements Comparable<ImageIdentifier>, Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    public static final ImageIdentifier NULL = new ImageIdentifier(0, 0, 0, 0);
+
+    private final int seriesIndex;
+
+    private final int timeSeriesIndex;
+
+    private final int focalPlaneIndex;
+
+    private final int colorChannelIndex;
+
+    /**
+     * Creates an instance for the specified series index, time series (or T) index, focal plane (or
+     * Z) index, color channel index.
+     */
+    public ImageIdentifier(int seriesIndex, int timeSeriesIndex, int focalPlaneIndex,
+            int colorChannelIndex)
+    {
+        this.seriesIndex = seriesIndex;
+        this.timeSeriesIndex = timeSeriesIndex;
+        this.focalPlaneIndex = focalPlaneIndex;
+        this.colorChannelIndex = colorChannelIndex;
+    }
+
+    public int getSeriesIndex()
+    {
+        return seriesIndex;
+    }
+
+    public int getTimeSeriesIndex()
+    {
+        return timeSeriesIndex;
+    }
+
+    public int getFocalPlaneIndex()
+    {
+        return focalPlaneIndex;
+    }
+
+    public int getColorChannelIndex()
+    {
+        return colorChannelIndex;
+    }
+
+    public String getUniqueStringIdentifier()
+    {
+        return new ImageID(getSeriesIndex(), getTimeSeriesIndex(), getFocalPlaneIndex(),
+                getColorChannelIndex()).getID();
+    }
+
+    @Override
+    public int compareTo(ImageIdentifier that)
+    {
+        int diff = seriesIndex - that.seriesIndex;
+        if (diff != 0)
+        {
+            return diff;
+        }
+        diff = timeSeriesIndex - that.timeSeriesIndex;
+        if (diff != 0)
+        {
+            return diff;
+        }
+        diff = focalPlaneIndex - that.focalPlaneIndex;
+        if (diff != 0)
+        {
+            return diff;
+        }
+        return colorChannelIndex - that.colorChannelIndex;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+        if (obj instanceof ImageIdentifier == false)
+        {
+            return false;
+        }
+        ImageIdentifier that = (ImageIdentifier) obj;
+        return seriesIndex == that.seriesIndex && timeSeriesIndex == that.timeSeriesIndex
+                && focalPlaneIndex == that.focalPlaneIndex
+                && colorChannelIndex == that.colorChannelIndex;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return ((((seriesIndex * 37) + timeSeriesIndex) * 37) + focalPlaneIndex) * 37
+                + colorChannelIndex;
+    }
+
+    @Override
+    public String toString()
+    {
+        return seriesIndex + "." + timeSeriesIndex + "." + focalPlaneIndex + "."
+                + colorChannelIndex;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageMetadata.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageMetadata.java
new file mode 100644
index 0000000000000000000000000000000000000000..5198c5e9be1fbbe381d01649e75c8934561d5319
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageMetadata.java
@@ -0,0 +1,160 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
+
+import org.apache.commons.lang.StringUtils;
+
+
+/**
+ * Store well, channel and tile number to which an image belongs. Optionally stores
+ * timepoint/depth-scan/image series number.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ImageMetadata
+{
+    private String channelCode;
+
+    private int tileNumber;
+
+    private String well;
+
+    private Float timepointOrNull;
+
+    private Float depthOrNull;
+
+    private Integer seriesNumberOrNull;
+
+    private ImageIdentifier imageIdentifierOrNull;
+
+    public String getChannelCode()
+    {
+        return channelCode;
+    }
+
+    /** Sets channel code. */
+    public void setChannelCode(String channelCode)
+    {
+        this.channelCode = channelCode;
+    }
+
+    public int getTileNumber()
+    {
+        return tileNumber;
+    }
+
+    /** Sets tile number. It should start from 1. */
+    public void setTileNumber(int tileNumber)
+    {
+        this.tileNumber = tileNumber;
+    }
+
+    public String getWell()
+    {
+        return well;
+    }
+
+    /** Sets well code (example: "A1") */
+    public void setWell(String well)
+    {
+        this.well = well;
+    }
+
+    /** Sets the timepoint of the image. Optional. */
+    public void setTimepoint(Float value)
+    {
+        this.timepointOrNull = value;
+    }
+
+    /** Sets the depth at which the image has been scanned. Optional. */
+    public void setDepth(Float value)
+    {
+        this.depthOrNull = value;
+    }
+
+    /**
+     * Sets the integer series number of the image. Optional. Used to order images when there are no
+     * time or depth dimentions but there is a series of images for one well, channel and tile. Can
+     * be also used together with time and depth dimention.
+     */
+    public void setSeriesNumber(Integer value)
+    {
+        this.seriesNumberOrNull = value;
+    }
+
+    /**
+     * Sets the id of the image inside a container image file format. This is optional and not
+     * needed for image files which contain only one image.
+     */
+    public void setImageIdentifier(ImageIdentifier imageIdentifier)
+    {
+        imageIdentifierOrNull = imageIdentifier;
+    }
+
+    public Float tryGetTimepoint()
+    {
+        return timepointOrNull;
+    }
+
+    public Float tryGetDepth()
+    {
+        return depthOrNull;
+    }
+
+    public Integer tryGetSeriesNumber()
+    {
+        return seriesNumberOrNull;
+    }
+
+    public ImageIdentifier tryGetImageIdentifier()
+    {
+        return imageIdentifierOrNull;
+    }
+
+    /**
+     * Validates that tile number, channel and well (if argument is <code>false</code>) have been
+     * specified.
+     * 
+     * @throws IllegalStateException if the object is not valid.
+     */
+    public void ensureValid(boolean isMicroscopy)
+    {
+        if (tileNumber <= 0)
+        {
+            throw new IllegalStateException("Tile number has to be > 0, but is " + tileNumber);
+        }
+        if (StringUtils.isBlank(channelCode))
+        {
+            throw new IllegalStateException("Channel code is not specified");
+        }
+        if (StringUtils.isBlank(well) && isMicroscopy == false)
+        {
+            throw new IllegalStateException("Well is not specified");
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append("ImageMetadata [channelCode=" + channelCode + ", tileNumber=" + tileNumber
+                + ", well=" + well);
+        if (timepointOrNull != null)
+        {
+            sb.append(", timepointOrNull =" + timepointOrNull);
+        }
+        if (depthOrNull != null)
+        {
+            sb.append(", depthOrNull=" + depthOrNull);
+        }
+        if (seriesNumberOrNull != null)
+        {
+            sb.append(", seriesNumberOrNull=" + seriesNumberOrNull);
+        }
+        if (imageIdentifierOrNull != null)
+        {
+            sb.append(", imageIdentifierOrNull=" + imageIdentifierOrNull);
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageStorageConfiguraton.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageStorageConfiguraton.java
new file mode 100644
index 0000000000000000000000000000000000000000..720abe63ca0337e451a2505724e80902e93c0912
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ImageStorageConfiguraton.java
@@ -0,0 +1,205 @@
+/*
+ * 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.dss.etl.dto.api;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.common.reflection.AbstractHashable;
+import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+
+/**
+ * Configuration of how images should be stored. By default:
+ * <UL>
+ * <LI>no thumbnails are generated</LI>
+ * <LI>original data are stored as they come (without additional compression).</LI>
+ * </UL>
+ * 
+ * @author Tomasz Pylak
+ */
+public class ImageStorageConfiguraton extends AbstractHashable implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /** Returns the default configuration. */
+    public static ImageStorageConfiguraton createDefault()
+    {
+        return new ImageStorageConfiguraton();
+    }
+
+    // --- State ----------
+
+    /** No thumbnails are generated by default. */
+    private List<ThumbnailsStorageFormat> thumbnailsStorageFormatsList =
+            new ArrayList<ThumbnailsStorageFormat>();
+
+    private OriginalDataStorageFormat originalDataStorageFormat =
+            OriginalDataStorageFormat.UNCHANGED;
+
+    /** No preferences by default, each storage processor decides by its own if it is not set. */
+    private Boolean storeChannelsOnExperimentLevelOrNull = null;
+
+    /**
+     * an image transformation to be applied before the image is stored.
+     */
+    private IImageTransformerFactory imageTransformerFactoryOrNull;
+
+    /**
+     * null by default, in this case some heuristics are used to find the right library to read the
+     * images, but it is slower and not all libraries are tried.
+     */
+    private ImageLibraryInfo imageLibraryOrNull = null;
+
+    // --- Getters & Setters ----------
+
+    /** @return null if no thumbnails should be generated */
+    public List<ThumbnailsStorageFormat> getThumbnailsStorageFormat()
+    {
+        return thumbnailsStorageFormatsList;
+    }
+
+    /** Set to null if no thumbnails should be generated. Overrides previous thumbnails settings. */
+    public void setThumbnailsStorageFormat(ThumbnailsStorageFormat thumbnailsStorageFormatOrNull)
+    {
+        thumbnailsStorageFormatsList.clear();
+        addThumbnailsStorageFormat(thumbnailsStorageFormatOrNull);
+
+    }
+
+    /**
+     * Adds new thumbnails setting to the list
+     */
+    public void addThumbnailsStorageFormat(ThumbnailsStorageFormat thumbnailsStorageFormatOrNull)
+    {
+        if (thumbnailsStorageFormatOrNull != null)
+        {
+            thumbnailsStorageFormatsList.add(thumbnailsStorageFormatOrNull);
+        }
+    }
+
+    /**
+     * Convenience method to switch on thumbnails generation with default settings. Overrides the
+     * results of {@link #setThumbnailsStorageFormat(ThumbnailsStorageFormat)}!.
+     */
+    public void switchOnThumbnailsGeneration()
+    {
+        thumbnailsStorageFormatsList.clear();
+        thumbnailsStorageFormatsList.add(new ThumbnailsStorageFormat());
+    }
+
+    public OriginalDataStorageFormat getOriginalDataStorageFormat()
+    {
+        return originalDataStorageFormat;
+    }
+
+    public void setOriginalDataStorageFormat(OriginalDataStorageFormat originalDataStorageFormat)
+    {
+        this.originalDataStorageFormat = originalDataStorageFormat;
+    }
+
+    public void setOriginalDataStorageFormat(
+            ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.OriginalDataStorageFormat originalDataStorageFormat)
+    {
+        this.originalDataStorageFormat =
+                originalDataStorageFormat.getIndependentOriginalDataStorageFormat();
+    }
+
+    /**
+     * Signalizes that the channels should be saved on experiment level rather than dataset level.
+     * Will be ignored in case of microscopy where all channels are always saved at dataset level.
+     */
+    public void setStoreChannelsOnExperimentLevel(boolean storeChannelsOnExperimentLevel)
+    {
+        this.storeChannelsOnExperimentLevelOrNull = storeChannelsOnExperimentLevel;
+    }
+
+    public Boolean getStoreChannelsOnExperimentLevel()
+    {
+        return storeChannelsOnExperimentLevelOrNull;
+    }
+
+    public IImageTransformerFactory getImageTransformerFactory()
+    {
+        return imageTransformerFactoryOrNull;
+    }
+
+    /**
+     * Allows for applying an image transformation on the fly when an image is fetched.
+     */
+    public void setImageTransformerFactory(IImageTransformerFactory transformerFactory)
+    {
+        this.imageTransformerFactoryOrNull = transformerFactory;
+    }
+
+    /** Sets the library which should be used to read the images. */
+    public void setImageLibrary(ImageLibraryInfo imageLibrary)
+    {
+        this.imageLibraryOrNull = imageLibrary;
+    }
+
+    /**
+     * @return library which should be used to read the images or null if the library is not
+     *         specified.
+     */
+    public ImageLibraryInfo tryGetImageLibrary()
+    {
+        return imageLibraryOrNull;
+    }
+
+    @Override
+    public String toString()
+    {
+        final StringBuilder buffer = new StringBuilder(super.toString());
+        if (originalDataStorageFormat != OriginalDataStorageFormat.UNCHANGED)
+        {
+            appendNameAndObject(buffer, "original data storage format",
+                    originalDataStorageFormat.toString());
+        }
+        if (thumbnailsStorageFormatsList.size() > 0)
+        {
+            for (ThumbnailsStorageFormat thumbnailsStorageFormat : thumbnailsStorageFormatsList)
+            {
+                appendNameAndObject(buffer, "thumbnails", thumbnailsStorageFormat.toString());
+            }
+        }
+        if (storeChannelsOnExperimentLevelOrNull != null)
+        {
+            appendNameAndObject(buffer, "store channels on experiment level",
+                    storeChannelsOnExperimentLevelOrNull);
+        }
+        if (imageTransformerFactoryOrNull != null)
+        {
+            appendNameAndObject(buffer, "image transformation", "present");
+        }
+        if (imageLibraryOrNull != null)
+        {
+            appendNameAndObject(buffer, "image library", imageLibraryOrNull.toString());
+        }
+        return buffer.toString();
+    }
+
+    protected static final void appendNameAndObject(final StringBuilder buffer, final String name,
+            final Object object)
+    {
+        if (object != null)
+        {
+            buffer.append(name).append("::").append(object).append(";");
+        }
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IntensityRange.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IntensityRange.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd3d95145432e17cf50b6a6007cb1e791ee9abcd
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IntensityRange.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012 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.etl.dto.api;
+
+/**
+ * The intensity range in a distribution of pixel values for a given symmetric quantile value.
+ *
+ * @author Bernd Rinn
+ */
+public class IntensityRange
+{
+    final int blackPoint;
+
+    final int whitePoint;
+
+    public IntensityRange(int blackPoint, int whitePoint)
+    {
+        this.blackPoint = blackPoint;
+        this.whitePoint = whitePoint;
+    }
+
+    /**
+     * The minimal level (black point).
+     */
+    public int getBlackPoint()
+    {
+        return blackPoint;
+    }
+
+    /**
+     * The maximal level (white point).
+     */
+    public int getWhitePoint()
+    {
+        return whitePoint;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "MinMax [minLevel=" + blackPoint + ", maxLevel=" + whitePoint + "]";
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/Location.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/Location.java
new file mode 100644
index 0000000000000000000000000000000000000000..4650487b462c0b39162090c0490c0076fa279dbf
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/Location.java
@@ -0,0 +1,63 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
+
+/**
+ * Auxiliary structure to store tile location on the well. The top left tile has coordinates (1,1).
+ * 
+ * @author Tomasz Pylak
+ */
+public class Location
+{
+    private final int row, column;
+
+    /** Note: The top left tile has coordinates (1,1). */
+    public Location(int row, int column)
+    {
+        this.row = row;
+        this.column = column;
+    }
+
+    public int getRow()
+    {
+        return row;
+    }
+
+    public int getColumn()
+    {
+        return column;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        Location other = (Location) obj;
+        return column == other.column && row == other.row;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + column;
+        result = prime * result + row;
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "[" + row + ":" + column + "]";
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/OriginalDataStorageFormat.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/OriginalDataStorageFormat.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7a67435b503e49d2af3c9b4aca5814efbb6d9b3
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/OriginalDataStorageFormat.java
@@ -0,0 +1,41 @@
+/*
+ * 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.dss.etl.dto.api;
+
+/**
+ * How original dataset data should be stored.
+ * 
+ * @author Tomasz Pylak
+ */
+public enum OriginalDataStorageFormat
+{
+    /** original data are stored as they come (without additional compression) */
+    UNCHANGED,
+
+    /** original data are stored in one HDF5 container (uncompressed) */
+    HDF5,
+
+    /** original data are stored in one HDF5 container (compressed) */
+    HDF5_COMPRESSED;
+
+    public boolean isHdf5()
+    {
+        return this == OriginalDataStorageFormat.HDF5
+                || this == OriginalDataStorageFormat.HDF5_COMPRESSED;
+    }
+
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageContainerDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageContainerDataConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..8b5baffe59cfd79350dcaeeca30d6ad246164bd6
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageContainerDataConfig.java
@@ -0,0 +1,70 @@
+/*
+ * 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.dss.etl.dto.api;
+
+import java.util.List;
+
+
+/**
+ * Subclass of {@link SimpleImageDataConfig} for container image files which creates
+ * {@link ImageMetadata} based on {@link ImageIdentifier} using the following simple mapping:
+ * <ul>
+ * <li>ImageMetadata.seriesNumber = ImageIdentifier.seriesIndex + 1
+ * <li>ImageMetadata.timePoint = ImageIdentifier.timeSeriesIndex
+ * <li>ImageMetadata.depth = ImageIdentifier.focalPlaneIndex
+ * <li>ImageMetadata.channelCode = 'CHANNEL-' + (ImageIdentifier.colorChannelIndex + 1)
+ * <li>ImageMetadata.tileNumber = 1
+ * </ul>
+ * ImageMetadata.well will be filled with return value of method
+ * {@link #tryToExtractWell(ImageIdentifier)}.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public class SimpleImageContainerDataConfig extends SimpleImageDataConfig
+{
+
+    @Override
+    public ImageMetadata[] extractImagesMetadata(String imagePath,
+            List<ImageIdentifier> imageIdentifiers)
+    {
+        ImageMetadata[] metaData = new ImageMetadata[imageIdentifiers.size()];
+        for (int i = 0, n = imageIdentifiers.size(); i < n; i++)
+        {
+            ImageIdentifier imageIdentifier = imageIdentifiers.get(i);
+            ImageMetadata imageMetadata = new ImageMetadata();
+            imageMetadata.setImageIdentifier(imageIdentifier);
+            imageMetadata.setSeriesNumber(imageIdentifier.getSeriesIndex() + 1);
+            imageMetadata.setTimepoint(new Float(imageIdentifier.getTimeSeriesIndex()));
+            imageMetadata.setDepth(new Float(imageIdentifier.getFocalPlaneIndex()));
+            imageMetadata.setChannelCode("CHANNEL-" + (imageIdentifier.getColorChannelIndex() + 1));
+            imageMetadata.setWell(tryToExtractWell(imageIdentifier));
+            imageMetadata.setTileNumber(1);
+            metaData[i] = imageMetadata;
+        }
+        return metaData;
+    }
+
+    /**
+     * Tries to extract well from the specified image identifier. Default implementation returns
+     * <code>null</code>. In case of screening this method can be overridden.
+     */
+    public String tryToExtractWell(ImageIdentifier imageIdentifier)
+    {
+        return null;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageDataConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..e39c0e858bfbc83ae9afcda6fe847de4ee66522c
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageDataConfig.java
@@ -0,0 +1,988 @@
+/*
+ * 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.dss.etl.dto.api;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.common.shared.basic.string.StringUtils;
+import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.DefaultThumbnailsConfiguration;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.IThumbnailsConfiguration;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.ResolutionBasedThumbnailsConfiguration;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.ZoomLevelBasedThumbnailsConfiguration;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ConvertToolImageTransformerFactory;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformationBuffer;
+import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
+import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
+
+/**
+ * Allows to configure extraction of images for a plate or microscopy sample.
+ * 
+ * @author Tomasz Pylak
+ */
+abstract public class SimpleImageDataConfig
+{
+    // --- one of the following two methods has to be overridden -----------------
+
+    /**
+     * Extracts tile number, channel code and well code for a given relative path to a single image.
+     * This method should overridden to deal with files containing single images. It is ignored if
+     * {@link #extractImagesMetadata(String, List)} is overridden as well.
+     * <p>
+     * It will be called for each file found in the incoming directory which has the extension
+     * returned by {@link #getRecognizedImageExtensions()}.
+     * </p>
+     * To deal with image containers (like multi-page TIFF files) override
+     * {@link #extractImagesMetadata(String, List)} instead, otherwise leave that method unchanged.
+     */
+    public ImageMetadata extractImageMetadata(String imagePath)
+    {
+        throw new UnsupportedOperationException(
+                "One of the extractImageMetadata() methods has to be implemented.");
+    }
+
+    /**
+     * Returns meta-data for each image in the specified image container. This method should
+     * overridden to deal with container images (like multi-page TIFF files).
+     * <p>
+     * This implementation returns the result of {@link #extractImageMetadata(String)} wrapped in an
+     * array, image identifiers are ignored.
+     * </p>
+     * 
+     * @param imagePath path to the single image or container of many images
+     * @param imageIdentifiers Identifiers of all images contained in the image file.
+     */
+    public ImageMetadata[] extractImagesMetadata(String imagePath,
+            List<ImageIdentifier> imageIdentifiers)
+    {
+
+        ImageMetadata imageMetadata = extractImageMetadata(imagePath);
+        return (imageMetadata != null) ? new ImageMetadata[]
+            { imageMetadata } : new ImageMetadata[0];
+    }
+
+    // --- methods which can be overridden -----------------
+
+    /**
+     * By default layouts all images in one row by returning (1, maxTileNumber) geometry.Can be
+     * overridden in subclasses.
+     * 
+     * @param imageMetadataList a list of metadata for each encountered image
+     * @param maxTileNumber the biggest tile number among all encountered images
+     * @return the width and height of the matrix of tiles (a.k.a. fields or sides) in the well.
+     */
+    public Geometry getTileGeometry(List<? extends ImageMetadata> imageMetadataList,
+            int maxTileNumber)
+    {
+        return Geometry.createFromRowColDimensions(1, maxTileNumber);
+    }
+
+    /**
+     * For a given tile number and tiles geometry returns (x,y) which describes where the tile is
+     * located on the well. Can be overridden in subclasses.<br>
+     * Note: The top left tile has coordinates (1,1).
+     * 
+     * @param tileNumber number of the tile extracted by {@link #extractImageMetadata}.
+     * @param tileGeometry the geometry of the well matrix returned by {@link #getTileGeometry}.
+     */
+    public Location getTileCoordinates(int tileNumber, Geometry tileGeometry)
+    {
+        int columns = tileGeometry.getWidth();
+        int row = ((tileNumber - 1) / columns) + 1;
+        int col = ((tileNumber - 1) % columns) + 1;
+        return new Location(row, col);
+    }
+
+    /**
+     * <p>
+     * Creates channel description for a given code. Can be overridden in subclasses.
+     * </p>
+     * By default the channel label will be equal to the code. Channel color returned by
+     * {@link #getChannelColor(String)} will be used.
+     */
+    public Channel createChannel(String channelCode)
+    {
+        ChannelColorRGB channelColorOrNull = tryGetChannelColor(channelCode.toUpperCase());
+        ImageTransformation[] availableTransformations =
+                getAvailableChannelTransformations(channelCode);
+        String label = channelCode;
+        String normalizedChannelCode = CodeNormalizer.normalize(channelCode);
+        Channel channel = new Channel(normalizedChannelCode, label, channelColorOrNull);
+        channel.setAvailableTransformations(availableTransformations);
+        return channel;
+    }
+
+    private ChannelColorRGB tryGetChannelColor(String channelCode)
+    {
+        ChannelColor channelColor = getChannelColor(channelCode);
+        ChannelColorRGB channelColorRGB = getChannelColorRGB(channelCode);
+        if (channelColorRGB != null && channelColor != null)
+        {
+            throw new IllegalStateException(String.format(
+                    "Color for channel '%s' is specified in two ways: %s and %s", channelColor,
+                    channelColorRGB));
+        }
+
+        if (channelColor != null)
+        {
+            return channelColor.getRGB();
+        } else
+        {
+            return channelColorRGB;
+        }
+    }
+
+    /**
+     * Sets available transformations which can be applied to images of the specified channel (on
+     * user's request).
+     * <p>
+     * Can be overridden in subclasses. The easiest way to create transformations is to use
+     * {@link ImageTransformationBuffer} class.
+     * <p>
+     * By default returns null.
+     */
+    public ImageTransformation[] getAvailableChannelTransformations(String channelCode)
+    {
+        return null;
+    }
+
+    /**
+     * Has the same effect as {@link #getChannelColorRGB(String)}, but can return only plain colors.
+     */
+    public ChannelColor getChannelColor(String channelCode)
+    {
+        return null;
+    }
+
+    /**
+     * Returns RGB color for the specified channel. It will be used to display merged channels
+     * images.
+     * <p>
+     * Can be overridden in subclasses. It is ignored if {@link #createChannel(String)} is
+     * overridden as well. One should not override {@link #getChannelColor(String)} and
+     * {@link #getChannelColorRGB(String)} at the same time.
+     * </p>
+     * By default returns null (the arbitrary color will be set).
+     */
+    public ChannelColorRGB getChannelColorRGB(String channelCode)
+    {
+        return null;
+    }
+
+    // --- auxiliary structures ----------------------------------------------
+
+    private String mainDatasetTypeCode;
+
+    private String fileFormatCode = ScreeningConstants.UNKNOWN_FILE_FORMAT;
+
+    private String plateCode;
+
+    private String spaceCode;
+
+    private boolean isMeasured = false;
+
+    private String[] recognizedImageExtensions = new String[]
+        { "tiff", "tif", "png", "gif", "jpg", "jpeg", "c01" };
+
+    private List<IThumbnailsConfiguration> imagePyramid = new ArrayList<IThumbnailsConfiguration>();
+
+    private int maxThumbnailWidthAndHeight = 256;
+
+    private boolean generateThumbnailsWithImageMagic = true;
+
+    private List<String> thumbnailsGenerationImageMagicParams = Collections.emptyList();
+
+    private boolean generateThumbnailsIn8BitHighQuality = false;
+
+    private double allowedMachineLoadDuringThumbnailsGeneration = 1.0;
+
+    private boolean storeChannelsOnExperimentLevel = false;
+
+    private OriginalDataStorageFormat originalDataStorageFormat =
+            OriginalDataStorageFormat.UNCHANGED;
+
+    private String convertTransformationCliArgumentsOrNull;
+
+    private ImageLibraryInfo imageLibraryInfoOrNull;
+
+    private boolean isMicroscopy;
+
+    // If null then no common intensity rescaling parameters are computed.
+    // If empty the computation will take place for all channels, otherwise only for specified
+    // channels.
+    private List<String> computeCommonIntensityRangeOfAllImagesForChannelsOrNull = null;
+
+    private float computeCommonIntensityRangeOfAllImagesThreshold =
+            ImageUtil.DEFAULT_IMAGE_OPTIMAL_RESCALING_FACTOR;
+
+    private String computeCommonIntensityRangeOfAllImagesLabel = "Optimal (series)";
+
+    private boolean computeCommonIntensityRangeOfAllImagesIsDefault = true;
+
+    private Map<String, IntensityRange> fixedIntensityRangeForAllImages;
+
+    private String thumbnailsFileFormat;
+
+    private List<Channel> channels;
+
+    private List<ChannelColorComponent> channelColorComponentsOrNull;
+
+    // --- getters & setters ----------------------------------------------
+
+    public ImageStorageConfiguraton getImageStorageConfiguration()
+    {
+        ImageStorageConfiguraton imageStorageConfiguraton =
+                ImageStorageConfiguraton.createDefault();
+        imageStorageConfiguraton
+                .setStoreChannelsOnExperimentLevel(isStoreChannelsOnExperimentLevel());
+        imageStorageConfiguraton.setOriginalDataStorageFormat(getOriginalDataStorageFormat());
+        for (IThumbnailsConfiguration thumbnailsConfiguration : imagePyramid)
+        {
+            imageStorageConfiguraton.addThumbnailsStorageFormat(thumbnailsConfiguration
+                    .getThumbnailsStorageFormat(this));
+        }
+        if (false == StringUtils.isBlank(convertTransformationCliArgumentsOrNull))
+        {
+            IImageTransformerFactory convertTransformerFactory =
+                    new ConvertToolImageTransformerFactory(convertTransformationCliArgumentsOrNull);
+            imageStorageConfiguraton.setImageTransformerFactory(convertTransformerFactory);
+
+        }
+        imageStorageConfiguraton.setImageLibrary(imageLibraryInfoOrNull);
+        return imageStorageConfiguraton;
+    }
+
+    public String getPlateSpace()
+    {
+        return spaceCode;
+    }
+
+    public String getPlateCode()
+    {
+        return plateCode;
+    }
+
+    public String[] getRecognizedImageExtensions()
+    {
+        return recognizedImageExtensions;
+    }
+
+    public boolean isGenerateThumbnails()
+    {
+        return imagePyramid.size() > 0;
+    }
+
+    public int getMaxThumbnailWidthAndHeight()
+    {
+        return maxThumbnailWidthAndHeight;
+    }
+
+    public double getAllowedMachineLoadDuringThumbnailsGeneration()
+    {
+        return allowedMachineLoadDuringThumbnailsGeneration;
+    }
+
+    public boolean isStoreChannelsOnExperimentLevel()
+    {
+        return storeChannelsOnExperimentLevel;
+    }
+
+    public OriginalDataStorageFormat getOriginalDataStorageFormat()
+    {
+        return originalDataStorageFormat;
+    }
+
+    public String tryGetConvertTransformationCliArguments()
+    {
+        return convertTransformationCliArgumentsOrNull;
+    }
+
+    public List<String> getComputeCommonIntensityRangeOfAllImagesForChannels()
+    {
+        return computeCommonIntensityRangeOfAllImagesForChannelsOrNull;
+    }
+
+    public float getComputeCommonIntensityRangeOfAllImagesThreshold()
+    {
+        return computeCommonIntensityRangeOfAllImagesThreshold;
+    }
+
+    public boolean isFixedIntensityRangeForAllImagesDefined()
+    {
+        return fixedIntensityRangeForAllImages != null;
+    }
+
+    public Map<String, IntensityRange> getFixedIntensityRangeForAllImages()
+    {
+        return fixedIntensityRangeForAllImages;
+    }
+
+    public String getComputeCommonIntensityRangeOfAllImagesLabel()
+    {
+        return computeCommonIntensityRangeOfAllImagesLabel;
+    }
+
+    public boolean isComputeCommonIntensityRangeOfAllImagesDefault()
+    {
+        return computeCommonIntensityRangeOfAllImagesIsDefault;
+    }
+
+    public List<Channel> getChannels()
+    {
+        return channels;
+    }
+
+    public List<ChannelColorComponent> getChannelColorComponentsOrNull()
+    {
+        return channelColorComponentsOrNull;
+    }
+
+    // ----- Setters -------------------------
+
+    /**
+     * Sets the existing plate to which the dataset should belong.
+     * 
+     * @param spaceCode space where the plate for which the dataset has been acquired exist
+     * @param plateCode code of the plate to which the dataset will belong
+     */
+    public void setPlate(String spaceCode, String plateCode)
+    {
+        this.spaceCode = spaceCode;
+        this.plateCode = plateCode;
+    }
+
+    /**
+     * Only files with these extensions will be recognized as images (e.g. ["jpg", "png"]).<br>
+     * By default it is set to [ "tiff", "tif", "png", "gif", "jpg", "jpeg", "c01" ].
+     */
+    public void setRecognizedImageExtensions(String[] recognizedImageExtensions)
+    {
+        this.recognizedImageExtensions = recognizedImageExtensions;
+    }
+
+    /** Sets all channels available in the data set. */
+    public void setChannels(List<Channel> channels)
+    {
+        this.channels = channels;
+    }
+
+    /**
+     * Use this method if channels are encoded in color components of one image (or in other words:
+     * each image contains merged channels). For each channel you have to specify the corresponding
+     * color component of the image.
+     */
+    public void setChannels(List<Channel> channels,
+            List<ChannelColorComponent> channelColorComponents)
+    {
+        this.channels = channels;
+        channelColorComponentsOrNull = channelColorComponents;
+    }
+
+    /** should thumbnails be generated? False by default. */
+    public void setGenerateThumbnails(boolean generateThumbnails)
+    {
+        imagePyramid.clear();
+        imagePyramid.add(new DefaultThumbnailsConfiguration());
+    }
+
+    /**
+     * See {@link #setGenerateImageRepresentations}.
+     * 
+     * @deprecated use {@link #setGenerateImageRepresentations} instead.
+     */
+    @Deprecated
+    public void setGenerateImagePyramid(IThumbnailsConfiguration[] elements)
+    {
+        setGenerateImageRepresentations(elements);
+    }
+
+    /**
+     * See {@link #setGenerateImageRepresentationsUsingScaleFactors}.
+     * 
+     * @deprecated use {@link #setGenerateImageRepresentationsUsingScaleFactors} instead.
+     */
+    @Deprecated
+    public void setGenerateImagePyramidWithScaleFactors(double[] zoomLevels)
+    {
+        setGenerateImageRepresentationsUsingScaleFactors(zoomLevels);
+    }
+
+    /**
+     * See {@link #setGenerateImageRepresentationsUsingImageResolutions}.
+     * 
+     * @deprecated use {@link #setGenerateImageRepresentationsUsingImageResolutions} instead.
+     */
+    @Deprecated
+    public void setGenerateImagePyramidWithImageResolution(String[] resolutions)
+    {
+        setGenerateImageRepresentationsUsingImageResolutions(resolutions);
+    }
+
+    /**
+     * Registers a request for alternate image representations to be generated based on the original
+     * image. The format of the alternate representations is specified by the
+     * {@link IThumbnailsConfiguration} formats argument.
+     * 
+     * @param formats The formats of the image generated representations. One image representation
+     *            will be created for each format.
+     */
+    public void setGenerateImageRepresentations(IThumbnailsConfiguration[] formats)
+    {
+        imagePyramid.clear();
+        imagePyramid.addAll(Arrays.asList(formats));
+    }
+
+    /**
+     * Registers a request for alternate image representations to be generated based on the original
+     * image. The alternate image representations vary with respect to resolution from the original
+     * image.
+     * 
+     * @param scaleFactors The scale factors applied to the original resolution. Scale factors must
+     *            be greater than 0.
+     */
+    public void setGenerateImageRepresentationsUsingScaleFactors(double[] scaleFactors)
+    {
+        imagePyramid.clear();
+        if (scaleFactors == null)
+        {
+            return;
+        }
+
+        // Verify the arguments
+        for (double scaleFactor : scaleFactors)
+        {
+            // This check is duplicated in addImageRepresentationUsingScale
+            if (scaleFactor <= 0)
+            {
+                throw new IllegalArgumentException(
+                        "Scale factors for generated image representations must be greater than 0. "
+                                + scaleFactor + " <= 0");
+            }
+        }
+        for (double scale : scaleFactors)
+        {
+            addGeneratedImageRepresentationWithScale(scale);
+        }
+    }
+
+    /**
+     * Registers a request for an alternate image representation to be generated based on the
+     * original image. The alternate image representations vary with respect to resolution from the
+     * original image.
+     * 
+     * @param scale The scale factor applied to the original resolution. Scale factors must be
+     *            greater than 0.
+     * @return The configuration for the image representation
+     */
+    public IThumbnailsConfiguration addGeneratedImageRepresentationWithScale(double scale)
+    {
+        if (scale <= 0)
+        {
+            throw new IllegalArgumentException(
+                    "Scale factors for generated image representations must be greater than 0. "
+                            + scale + " <= 0");
+        }
+        ZoomLevelBasedThumbnailsConfiguration imageRep =
+                new ZoomLevelBasedThumbnailsConfiguration(scale);
+        imagePyramid.add(imageRep);
+        return imageRep;
+    }
+
+    /**
+     * Registers a request for alternate image representations to be generated based on the original
+     * image. The alternate image representations vary with respect to resolution from the original
+     * image. By default, allow enlarging. Use
+     * {@link #setGenerateImageRepresentationsWithoutEnlargingUsingImageResolutions(String[])} to
+     * explicitly prevent enlarging.
+     * 
+     * @param resolutions The resolutions
+     */
+    public void setGenerateImageRepresentationsUsingImageResolutions(String[] resolutions)
+    {
+        setGenerateImageRepresentationsUsingImageResolutions(resolutions, true);
+    }
+
+    /**
+     * Registers a request for alternate image representations to be generated based on the original
+     * image. The alternate image representations vary with respect to resolution from the original
+     * image. This method throws an exception if the requested resolution results in the image being
+     * enlarged. Use {@link #setGenerateImageRepresentationsUsingImageResolutions(String[])} to
+     * allow enlarging.
+     * 
+     * @param resolutions The resolutions
+     */
+    public void setGenerateImageRepresentationsWithoutEnlargingUsingImageResolutions(
+            String[] resolutions)
+    {
+        setGenerateImageRepresentationsUsingImageResolutions(resolutions, false);
+    }
+
+    /**
+     * Registers a request for alternate image representations to be generated based on the original
+     * image. The alternate image representations vary with respect to resolution from the original
+     * image.
+     * 
+     * @param resolutions The resolutions
+     * @param allowEnlarging If true, resolutions larger than the original size of the image are
+     *            allowed
+     */
+    private void setGenerateImageRepresentationsUsingImageResolutions(String[] resolutions,
+            boolean allowEnlarging)
+    {
+        imagePyramid.clear();
+        if (resolutions != null)
+        {
+            for (String resolution : resolutions)
+            {
+                addGeneratedImageRepresentationWithResolution(resolution, allowEnlarging);
+            }
+        }
+    }
+
+    /**
+     * Registers a request for an alternate image representation to be generated based on the
+     * original image. The alternate image representations vary with respect to resolution from the
+     * original image. Enlarging is allowed. To prevent enlarging of the image, use
+     * {@link #addGeneratedImageRepresentationWithoutEnlargingWithResolution}.
+     * 
+     * @param resolution The resolution of the representation.
+     * @return The configuration for the image representation.
+     */
+    public IThumbnailsConfiguration addGeneratedImageRepresentationWithResolution(String resolution)
+    {
+        return addGeneratedImageRepresentationWithResolution(resolution, true);
+    }
+
+    /**
+     * Registers a request for an alternate image representation to be generated based on the
+     * original image. The alternate image representations vary with respect to resolution from the
+     * original image. Enlarging is not allowed. To allow enlarging of the image, use
+     * {@link #addGeneratedImageRepresentationWithResolution}.
+     * 
+     * @param resolution The resolution of the representation.
+     * @return The configuration for the image representation.
+     */
+    public IThumbnailsConfiguration addGeneratedImageRepresentationWithoutEnlargingWithResolution(
+            String resolution)
+    {
+        return addGeneratedImageRepresentationWithResolution(resolution, false);
+    }
+
+    /**
+     * Registers a request for an alternate image representation to be generated based on the
+     * original image. The alternate image representations vary with respect to resolution from the
+     * original image.
+     * 
+     * @param resolution The resolution of the representation.
+     * @param allowEnlarging If true, the generated representation may be <b>larger</b> than the
+     *            original image.
+     * @return The configuration for the image representation.
+     */
+    private IThumbnailsConfiguration addGeneratedImageRepresentationWithResolution(
+            String resolution, boolean allowEnlarging)
+    {
+        String[] dimension = resolution.split("x");
+        if (dimension.length != 2)
+        {
+            throw new IllegalArgumentException(
+                    "Resolution must be specified in format width x height, e. g. '400x300', but was: '"
+                            + resolution + "'");
+        }
+        int width = Integer.parseInt(dimension[0].trim());
+        int height = Integer.parseInt(dimension[1].trim());
+        ResolutionBasedThumbnailsConfiguration imageRep =
+                new ResolutionBasedThumbnailsConfiguration(width, height, allowEnlarging);
+        imagePyramid.add(imageRep);
+        return imageRep;
+    }
+
+    /** the maximal width and height of the generated thumbnails */
+    public void setMaxThumbnailWidthAndHeight(int maxThumbnailWidthAndHeight)
+    {
+        this.maxThumbnailWidthAndHeight = maxThumbnailWidthAndHeight;
+    }
+
+    /**
+     * Valid only if thumbnails generation is switched on. Set it to a value lower than 1 if you
+     * want only some of your processor cores to be used for thumbnails generation. Number of
+     * threads that are used for thumbnail generation will be equal to: this constant * number of
+     * processor cores.
+     */
+    public void setAllowedMachineLoadDuringThumbnailsGeneration(
+            double allowedMachineLoadDuringThumbnailsGeneration)
+    {
+        this.allowedMachineLoadDuringThumbnailsGeneration =
+                allowedMachineLoadDuringThumbnailsGeneration;
+    }
+
+    /**
+     * Decides if ImageMagic 'convert' utility will be used to generate thumbnails. True by default.
+     * <p>
+     * One should set this option to false and use the internal library if 'convert' tool is not
+     * installed or if many images are stored in one image container file.
+     */
+    public void setUseImageMagicToGenerateThumbnails(boolean generateWithImageMagic)
+    {
+        this.generateThumbnailsWithImageMagic = generateWithImageMagic;
+    }
+
+    public boolean getGenerateThumbnailsWithImageMagic()
+    {
+        return generateThumbnailsWithImageMagic;
+    }
+
+    /**
+     * Sets additional parameters which should be passed to ImageMagic 'convert' utility when it is
+     * used to generate thumbnails.
+     * <p>
+     * Example: pass "-contrast-stretch 2%" to discard 2% of brightest and darkest pixels in the
+     * thumbnails.
+     */
+    public void setThumbnailsGenerationImageMagicParams(String[] imageMagicParams)
+    {
+        this.thumbnailsGenerationImageMagicParams = Arrays.asList(imageMagicParams);
+    }
+
+    public List<String> getThumbnailsGenerationImageMagicParams()
+    {
+        return thumbnailsGenerationImageMagicParams;
+    }
+
+    /**
+     * If true and thumbnails generation is switched on, thumbnails will be generated with high
+     * quality.
+     * <p>
+     * Be careful: high quality means that the generation will take longer and the image will be
+     * converted to 8 bit color depth. This option is useful for segmentation images, images with 8
+     * bit color depth or when no 16 bit transformation has to be applied to the images.
+     */
+    public void setGenerateHighQuality8BitThumbnails(boolean highQualityThumbnails)
+    {
+        this.generateThumbnailsIn8BitHighQuality = highQualityThumbnails;
+    }
+
+    public boolean getGenerateThumbnailsIn8BitHighQuality()
+    {
+        return generateThumbnailsIn8BitHighQuality;
+    }
+
+    /**
+     * See {@link #setGenerateHighQuality8BitThumbnails}.
+     * 
+     * @deprecated use {@link #setGenerateHighQuality8BitThumbnails} instead.
+     */
+    @Deprecated
+    public void setGenerateHighQualityThumbnails(boolean highQualityThumbnails)
+    {
+        this.generateThumbnailsIn8BitHighQuality = highQualityThumbnails;
+    }
+
+    /**
+     * <p>
+     * Can be used only for grayscale images, Useful when images do not use the whole available
+     * color depth of the format in which they are stored (e.g. 10 bits out of 12). By default
+     * switched off. Causes that the conversion to 8 bit color depth looses less information. At the
+     * same time allows to compare images of one dataset to each other.<br>
+     * Warning: causes that all images have to be analysed before registration, this is a costly
+     * operation!
+     * </p>
+     * <p>
+     * If isComputed is set to true all dataset images will be analysed and one range of pixel
+     * intensities used across all images will be computed (with 0.5% threshold). The result will be
+     * saved and it will be possible to apply on-the-fly transformation when browsing images.
+     * </p>
+     * <p>
+     * Example: let's assume that all plate images are saved as 12 bit grayscales. Each image has
+     * ability to use pixel intensities from 0 to 4095. In our example only a range of the available
+     * intensities is used, let's say from 1024 to 2048. Before the image is displayed to the user
+     * it has to be converted to 8-bit color depth (range of intensities from 0 to 255). Without
+     * taking the effectively used intensities into account the range 1024...2048 would be converted
+     * to a range of 64..128 and other intensities would be unused. Analysing the images allows to
+     * convert 1024...2048 range to the full 0..255 range.
+     * </p>
+     */
+    public void setComputeCommonIntensityRangeOfAllImagesForAllChannels()
+    {
+        this.computeCommonIntensityRangeOfAllImagesForChannelsOrNull = Collections.emptyList();
+    }
+
+    /**
+     * See {@link #setComputeCommonIntensityRangeOfAllImagesForAllChannels()}.
+     * 
+     * @param channelCodesOrNull list of channel codes for which the optimal intensity rescaling
+     *            parameters will be computed. If empty all channels will be analysed. If null
+     *            nothing will be analysed (default behavior).
+     */
+    public void setComputeCommonIntensityRangeOfAllImagesForChannels(String[] channelCodesOrNull)
+    {
+        this.computeCommonIntensityRangeOfAllImagesForChannelsOrNull =
+                Arrays.asList(channelCodesOrNull);
+    }
+
+    /**
+     * Set the label of the transformation which will rescale dataset images intensities in an
+     * optimal and comparable way. Can be used if the default value is not appropriate.
+     * <p>
+     * See {@link #setComputeCommonIntensityRangeOfAllImagesForAllChannels()} for details.
+     */
+    public void setComputeCommonIntensityRangeOfAllImagesLabel(
+            String userFriendlyTransformationlabel)
+    {
+        this.computeCommonIntensityRangeOfAllImagesLabel = userFriendlyTransformationlabel;
+    }
+
+    /**
+     * Sets the threshold of intensities which should be ignored when computing common intensity
+     * range of all images. By default equal to 0.5%. Note that
+     * {@link #setComputeCommonIntensityRangeOfAllImagesForAllChannels()} or
+     * {@link #setComputeCommonIntensityRangeOfAllImagesForChannels(String[])} has to be called to
+     * switch on analysis.
+     * 
+     * @param threshold value from 0 to 1. If set to e.g. 0.1 then 10% of brightest and darkest
+     *            pixels will be ignored.
+     */
+    public void setComputeCommonIntensityRangeOfAllImagesThreshold(float threshold)
+    {
+        this.computeCommonIntensityRangeOfAllImagesThreshold = threshold;
+    }
+
+    /**
+     * Sets fixed levels for the common intensity range transformation for all images. If this one
+     * is set, the automatic level computation is switched off which may give big performance
+     * improvements. If the method
+     * {@link #setComputeCommonIntensityRangeOfAllImagesForChannels(String[])} is not called, will
+     * set the transformation for all channels.
+     */
+    public void setDefaultFixedIntensityRangeForAllImages(int minLevel, int maxLevel)
+    {
+        if (fixedIntensityRangeForAllImages == null)
+        {
+            fixedIntensityRangeForAllImages = new HashMap<String, IntensityRange>();
+        }
+        this.fixedIntensityRangeForAllImages.put(null, new IntensityRange(minLevel, maxLevel));
+    }
+
+    /**
+     * Add fixed levels for the common intensity range transformation of the given cannel for all
+     * images. If this one is set, the automatic level computation is switched off which can give
+     * big performance improvements.
+     * <p>
+     * Note: If {@link #setDefaultFixedIntensityRangeForAllImages(int, int)} is called as well, then
+     * the values provided here will overwrite the default values provided there for the channel
+     * <var>channelCode</var>. Otherwise, the common intensity transformation will only be computed
+     * for the channels where the levels have been set explicitly by this method.
+     */
+    public void addFixedIntensityRangeForAllImages(String channelCode, int minLevel, int maxLevel)
+    {
+        if (fixedIntensityRangeForAllImages == null)
+        {
+            fixedIntensityRangeForAllImages = new HashMap<String, IntensityRange>();
+        }
+        this.fixedIntensityRangeForAllImages.put(CodeNormalizer.normalize(channelCode),
+                new IntensityRange(minLevel, maxLevel));
+    }
+
+    /**
+     * Sets if the image transformation using common intensity range of all images should be the
+     * default choice when browsing images.
+     * <p>
+     * True by default, which means e.g. that the 'image optimal' transformation will not be
+     * automatically available for users. However one can still add it explicitly with a chosen
+     * threshold by redefining
+     * {@link SimpleImageDataConfig#getAvailableChannelTransformations(String)} method.
+     */
+    public void setComputeCommonIntensityRangeOfAllImagesIsDefault(boolean isDefault)
+    {
+        this.computeCommonIntensityRangeOfAllImagesIsDefault = isDefault;
+    }
+
+    /** Should all dataset in one experiment use the same channels? By default set to false. */
+    public void setStoreChannelsOnExperimentLevel(boolean storeChannelsOnExperimentLevel)
+    {
+        this.storeChannelsOnExperimentLevel = storeChannelsOnExperimentLevel;
+    }
+
+    /**
+     * Should the original data be stored in the original form or should we pack them into one
+     * container? Available values are {@link OriginalDataStorageFormat#UNCHANGED},
+     * {@link OriginalDataStorageFormat#HDF5}, {@link OriginalDataStorageFormat#HDF5_COMPRESSED}.
+     * The default is {@link OriginalDataStorageFormat#UNCHANGED}.
+     */
+    public void setOriginalDataStorageFormat(OriginalDataStorageFormat originalDataStorageFormat)
+    {
+        this.originalDataStorageFormat = originalDataStorageFormat;
+    }
+
+    public void setOriginalDataStorageFormat(
+            ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.OriginalDataStorageFormat originalDataStorageFormat)
+    {
+        this.originalDataStorageFormat =
+                originalDataStorageFormat.getIndependentOriginalDataStorageFormat();
+    }
+
+    /**
+     * Sets parameters for the 'convert' command line tool, which will be used to apply an image
+     * transformation on the fly when an image is fetched.
+     */
+    public void setConvertTransformationCliArguments(String convertTransformationCliArguments)
+    {
+        this.convertTransformationCliArgumentsOrNull = convertTransformationCliArguments;
+    }
+
+    /**
+     * Which image library and reader should be used to read the image? <br>
+     * Available libraries [readers]:<br>
+     * - IJ: [tiff]<br>
+     * - ImageIO: [jpg, bmp, jpeg, wbmp, png, gif]<br>
+     * - JAI: [pnm, jpeg, fpx, gif, tiff, wbmp, png, bmp]<br>
+     * - BioFormats: [ZipReader, APNGReader, JPEGReader, PGMReader, FitsReader, PCXReader,
+     * GIFReader, BMPReader, IPLabReader, IvisionReader, DeltavisionReader, MRCReader, GatanReader,
+     * GatanDM2Reader, ImarisReader, OpenlabRawReader, OMEXMLReader, LIFReader, AVIReader,
+     * PictReader, SDTReader, EPSReader, SlidebookReader, AliconaReader, MNGReader, KhorosReader,
+     * VisitechReader, LIMReader, PSDReader, InCellReader, L2DReader, FEIReader, NAFReader,
+     * MINCReader, QTReader, MRWReader, TillVisionReader, ARFReader, CellomicsReader, LiFlimReader,
+     * TargaReader, OxfordInstrumentsReader, VGSAMReader, HISReader, WATOPReader, SeikoReader,
+     * TopometrixReader, UBMReader, QuesantReader, BioRadGelReader, RHKReader,
+     * MolecularImagingReader, CellWorxReader, Ecat7Reader, VarianFDFReader, AIMReader, FakeReader,
+     * JEOLReader, NiftiReader, AnalyzeReader, APLReader, NRRDReader, ICSReader, PerkinElmerReader,
+     * AmiraReader, ScanrReader, BDReader, UnisokuReader, PDSReader, BioRadReader, FV1000Reader,
+     * ZeissZVIReader, IPWReader, ND2Reader, JPEG2000Reader, PCIReader, ImarisHDFReader,
+     * ZeissLSMReader, SEQReader, GelReader, ImarisTiffReader, FlexReader, SVSReader, ImaconReader,
+     * LEOReader, JPKReader, MIASReader, TCSReader, LeicaReader, NikonReader, FluoviewReader,
+     * PrairieReader, MetamorphReader, MicromanagerReader, ImprovisionTiffReader,
+     * MetamorphTiffReader, NikonTiffReader, OMETiffReader, PhotoshopTiffReader, FEITiffReader,
+     * SimplePCITiffReader, NikonElementsTiffReader, TiffDelegateReader, TextReader, BurleighReader,
+     * OpenlabReader, DicomReader, SMCameraReader, SBIGReader]
+     */
+    public void setImageLibrary(String imageLibraryName, String readerName)
+    {
+        this.imageLibraryInfoOrNull = new ImageLibraryInfo(imageLibraryName, readerName);
+    }
+
+    /**
+     * Sets the image library to be used for reading images. Available libraries are: IJ, ImageIO,
+     * JAI, and BioFormats. The first image file is used to determine the actual reader. Note, that
+     * all images are read with the same image reader.
+     */
+    public void setImageLibrary(String imageLibraryName)
+    {
+        this.imageLibraryInfoOrNull = new ImageLibraryInfo(imageLibraryName);
+    }
+
+    // --- predefined image dataset types
+
+    /**
+     * Sets dataset type to the one which should be used for storing raw images. Marks the dataset
+     * as a "measured" one.
+     */
+    public void setRawImageDatasetType()
+    {
+        setDataSetType(ScreeningConstants.DEFAULT_RAW_IMAGE_DATASET_TYPE);
+        setMeasuredData(true);
+    }
+
+    /**
+     * Sets dataset type to the one which should be used for storing overview images generated from
+     * raw images. Marks the dataset as a "derived" one.
+     */
+    public void setOverviewImageDatasetType()
+    {
+        setDataSetType(ScreeningConstants.DEFAULT_OVERVIEW_IMAGE_DATASET_TYPE);
+        setMeasuredData(false);
+    }
+
+    /**
+     * Sets dataset type to the one which should be used for storing overlay images. Marks the
+     * dataset as a "derived" one.
+     */
+    public void setSegmentationImageDatasetType()
+    {
+        setDataSetType(ScreeningConstants.DEFAULT_SEGMENTATION_IMAGE_DATASET_TYPE);
+        setMeasuredData(false);
+    }
+
+    // --- standard
+
+    /** Sets the type of the dataset. */
+    public void setDataSetType(String datasetTypeCode)
+    {
+        this.mainDatasetTypeCode = datasetTypeCode;
+    }
+
+    /** Sets the file type of the dataset. */
+    public void setFileFormatType(String fileFormatCode)
+    {
+        this.fileFormatCode = fileFormatCode;
+    }
+
+    /**
+     * Set whether the data is measured or not. By default false.
+     */
+    public void setMeasuredData(boolean isMeasured)
+    {
+        this.isMeasured = isMeasured;
+    }
+
+    /**
+     * Sets the microscopy flag which is by default <code>false</code>. This flag is used to check
+     * whether well in {@link ImageMetadata} is specified or not. In case of microscopy well is
+     * ignored. Otherwise it is mandatory.
+     */
+    public void setMicroscopyData(boolean isMicroscopy)
+    {
+        this.isMicroscopy = isMicroscopy;
+    }
+
+    public String getDataSetType()
+    {
+        return mainDatasetTypeCode;
+    }
+
+    public String getFileFormatType()
+    {
+        return fileFormatCode;
+    }
+
+    public boolean isMeasuredData()
+    {
+        return isMeasured;
+    }
+
+    public boolean isMicroscopyData()
+    {
+        return isMicroscopy;
+    }
+
+    public void setThumbnailsFileFormat(String thumbnailsFileFormat)
+    {
+        this.thumbnailsFileFormat = thumbnailsFileFormat;
+    }
+
+    public String getThumbnailsFileFormat()
+    {
+        return this.thumbnailsFileFormat;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleOverviewImageDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleOverviewImageDataConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..4934320a8c1f3c73241f4d09ad47c431e19b6037
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleOverviewImageDataConfig.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012 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.etl.dto.api;
+
+/**
+ * * Allows to configure extraction of overview images for a plate or microscopy sample.
+ * 
+ * @author Pawel Glyzewski
+ */
+public class SimpleOverviewImageDataConfig extends SimpleImageDataConfig
+{
+    private String containerDataSetCode;
+
+    private boolean generateOverviewImagesFromRegisteredImages;
+
+    public String getContainerDataSetCode()
+    {
+        return containerDataSetCode;
+    }
+
+    public void setContainerDataSetCode(String containerDataSetCode)
+    {
+        this.containerDataSetCode = containerDataSetCode;
+    }
+
+    public boolean isGenerateOverviewImagesFromRegisteredImages()
+    {
+        return generateOverviewImagesFromRegisteredImages;
+    }
+
+    public void setGenerateOverviewImagesFromRegisteredImages(
+            boolean generateOverviewImagesFromRegisteredImages)
+    {
+        this.generateOverviewImagesFromRegisteredImages =
+                generateOverviewImagesFromRegisteredImages;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ThumbnailsStorageFormat.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ThumbnailsStorageFormat.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4c502ff7ebbdf659f6821605deebc7adb64e221
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ThumbnailsStorageFormat.java
@@ -0,0 +1,332 @@
+/*
+ * 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.dss.etl.dto.api;
+
+import java.awt.image.BufferedImage;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ch.systemsx.cisd.common.reflection.AbstractHashable;
+import ch.systemsx.cisd.openbis.dss.Constants;
+import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
+
+/**
+ * Configuration parameters which describe how thumbnails should be generated.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ThumbnailsStorageFormat extends AbstractHashable implements Serializable
+{
+
+    private static final long serialVersionUID = 1L;
+
+    public enum FileFormat
+    {
+        PNG
+        {
+            @Override
+            public void writeImage(BufferedImage image, OutputStream stream)
+            {
+                ImageUtil.writeImageToPng(image, stream);
+            }
+
+            @Override
+            public String getFileExtension()
+            {
+                return "png";
+            }
+
+            @Override
+            public String getImageMagickParam()
+            {
+                return "png";
+            }
+        },
+        JPEG
+        {
+            @Override
+            public void writeImage(BufferedImage image, OutputStream stream)
+            {
+                ImageUtil.writeImageUsingImageIO(image, stream, "jpg");
+            }
+
+            @Override
+            public String getFileExtension()
+            {
+                return "jpg";
+            }
+
+            @Override
+            public String getImageMagickParam()
+            {
+                return "jpeg";
+            }
+        },
+        JPEG_2000
+        {
+            @Override
+            public void writeImage(BufferedImage image, OutputStream stream)
+            {
+                ImageUtil.writeImageUsingImageIO(image, stream, "jpeg 2000");
+            }
+
+            @Override
+            public String getFileExtension()
+            {
+                return "jp2";
+            }
+
+            @Override
+            public String getImageMagickParam()
+            {
+                return "jp2";
+            }
+        };
+
+        private static final Map<String, FileFormat> formats;
+        static
+        {
+            formats = new HashMap<String, ThumbnailsStorageFormat.FileFormat>();
+            for (FileFormat format : FileFormat.values())
+            {
+                formats.put(format.name().toUpperCase(), format);
+            }
+            formats.put("JP2", JPEG_2000);
+            formats.put("JPEG 2000", JPEG_2000);
+            formats.put("JPG", JPEG);
+        }
+
+        public abstract void writeImage(BufferedImage image, OutputStream stream);
+
+        public abstract String getFileExtension();
+
+        public abstract String getImageMagickParam();
+
+        public String getOpenBISFileType()
+        {
+            return getFileExtension().toUpperCase();
+        }
+
+        public static FileFormat getValue(String fileFormat)
+        {
+            return formats.get(fileFormat.toUpperCase());
+        }
+    }
+
+    /** Maximum default width and height of a thumbnail */
+    public static final int DEFAULT_THUMBNAIL_MAX_SIZE = 200;
+
+    /** Maximum default width and height of a thumbnail */
+    public static final boolean DEFAULT_COMPRESS_THUMBNAILS = false;
+
+    // ---
+
+    private int maxWidth = DEFAULT_THUMBNAIL_MAX_SIZE;
+
+    private int maxHeight = DEFAULT_THUMBNAIL_MAX_SIZE;
+
+    private boolean allowEnlarging = true;
+
+    private Double zoomLevel = null;
+
+    private boolean storeCompressed = DEFAULT_COMPRESS_THUMBNAILS;
+
+    private double allowedMachineLoadDuringGeneration = 1;
+
+    private boolean highQuality8Bit = false;
+
+    private boolean generateWithImageMagic = false;
+
+    private List<String> imageMagicParams = Collections.emptyList();
+
+    private String thumbnailsFileName;
+
+    private FileFormat fileFormat = FileFormat.PNG;
+
+    private final Map<String, String> transformations = new HashMap<String, String>();
+
+    /**
+     * Creates empty object which instructs that the thumbnails should be generated with default
+     * settings. Use setters to change default behaviour (you will probably not have to).
+     */
+    public ThumbnailsStorageFormat()
+    {
+    }
+
+    public int getMaxWidth()
+    {
+        return maxWidth;
+    }
+
+    public int getMaxHeight()
+    {
+        return maxHeight;
+    }
+
+    public boolean isStoreCompressed()
+    {
+        return storeCompressed;
+    }
+
+    public double getAllowedMachineLoadDuringGeneration()
+    {
+        return allowedMachineLoadDuringGeneration;
+    }
+
+    public boolean isHighQuality()
+    {
+        return highQuality8Bit;
+    }
+
+    public boolean isGenerateWithImageMagic()
+    {
+        return generateWithImageMagic;
+    }
+
+    public List<String> getImageMagicParams()
+    {
+        return imageMagicParams;
+    }
+
+    public boolean isAllowEnlarging()
+    {
+        return allowEnlarging;
+    }
+
+    // --- setters ---
+
+    /** Sets the maximum width of a thumbnail. */
+    public void setMaxWidth(int maxWidth)
+    {
+        this.maxWidth = maxWidth;
+    }
+
+    /** Sets the maximum height of a thumbnail. */
+    public void setMaxHeight(int maxHeight)
+    {
+        this.maxHeight = maxHeight;
+    }
+
+    /** Sets if each thumbnail should be additionally compressed (lostless) before it is stored. */
+    public void setStoreCompressed(boolean storeCompressed)
+    {
+        this.storeCompressed = storeCompressed;
+    }
+
+    /**
+     * Specify if this image representation is allowed to be larger than the original image.
+     */
+    public void setAllowEnlarging(boolean allowEnlarging)
+    {
+        this.allowEnlarging = allowEnlarging;
+    }
+
+    /**
+     * The number of threads which will be used during thumbnails generation will be equal to number
+     * of processor cores * machineLoad.
+     */
+    public void setAllowedMachineLoadDuringGeneration(double machineLoad)
+    {
+        this.allowedMachineLoadDuringGeneration = machineLoad;
+    }
+
+    /**
+     * Set to true if you want your thumbnails to be of higher quality. In such a case thumbnails
+     * generation during dataset registration will take longer. Recommended for overlay images.
+     */
+    public void setHighQuality(boolean highQuality)
+    {
+        this.highQuality8Bit = highQuality;
+    }
+
+    /**
+     * if true ImageMagic 'convert' utility should be installed and will be used to generate
+     * thumbnails. <br>
+     * Note: if images should be handled with a specific image library, it will be ignored for
+     * thumbnails generation if 'convert' is supposed to be used. Make sure that 'convert' can deal
+     * with your images in such a case.
+     */
+    public void setGenerateWithImageMagic(boolean generateWithImageMagic)
+    {
+        this.generateWithImageMagic = generateWithImageMagic;
+    }
+
+    /**
+     * Sets additional parameters which should be passed to ImageMagic 'convert' utility when it is
+     * used to generate thumbnails. Example: pass "-contrast-stretch 2%" to discard 2% of brightest
+     * and darkest pixels in the thumbnails.
+     */
+    public void setImageMagicParams(List<String> imageMagicParams)
+    {
+        this.imageMagicParams = imageMagicParams;
+    }
+
+    public Double getZoomLevel()
+    {
+        return zoomLevel;
+    }
+
+    public void setZoomLevel(Double zoomLevel)
+    {
+        this.zoomLevel = zoomLevel;
+    }
+
+    public String getThumbnailsFileName()
+    {
+        return thumbnailsFileName == null ? Constants.HDF5_CONTAINER_THUMBNAILS_FILE_NAME
+                : thumbnailsFileName;
+    }
+
+    public void setThumbnailsFileName(String thumbnailsFileName)
+    {
+        this.thumbnailsFileName = thumbnailsFileName;
+    }
+
+    public void setFileFormat(String fileFormat)
+    {
+        FileFormat value = FileFormat.getValue(fileFormat);
+        if (value == null)
+        {
+            throw new IllegalArgumentException("File format '" + fileFormat + "' is unknown");
+        }
+        this.fileFormat = value;
+    }
+
+    public FileFormat getFileFormat()
+    {
+        return fileFormat;
+    }
+
+    public void setTransformations(Map<String, String> transformations)
+    {
+        this.transformations.putAll(transformations);
+    }
+
+    public String getTransformationCode(String channelCode)
+    {
+        return transformations.get(channelCode.toUpperCase());
+    }
+
+    public Map<String, String> getTransformations()
+    {
+        return transformations;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinition.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinition.java
index 409ba08141fc91ba5d19f0efa5164aa3e64abaf0..3d8cc97d3948a89fabeab6d4f33c73b873e9155b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinition.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinition.java
@@ -25,7 +25,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeatureDefinition;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeatureDefinition;
 import ch.systemsx.cisd.openbis.dss.etl.featurevector.CanonicalFeatureVector;
 import ch.systemsx.cisd.openbis.dss.etl.featurevector.FeatureValuesMap;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSetInformation.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSetInformation.java
index d1055fc2878570077fa39322baf3cd3a520faed3..4415f1b0ab1629faa3ccf7848771386150dbbc3a 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSetInformation.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSetInformation.java
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import ch.systemsx.cisd.common.shared.basic.string.StringUtils;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeatureDefinition;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeatureDefinition;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeaturesBuilder.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeaturesBuilder.java
index 74ea5506fbb2e98260aca331b41c4d2f4996fea1..6011f108603faa8c1b50ea7c8b7ef7e6bdd6d959 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeaturesBuilder.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeaturesBuilder.java
@@ -20,8 +20,8 @@ import java.util.ArrayList;
 import java.util.List;
 
 import ch.systemsx.cisd.common.shared.basic.string.StringUtils;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeatureDefinition;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeaturesBuilder;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeatureDefinition;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeaturesBuilder;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO;
 
 /**
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetInformation.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetInformation.java
index cc8817028732a712f8f17b3e9fa892fe7f554ba6..8c5d0b842526be8702980bb36c32eabfe2d83789 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetInformation.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetInformation.java
@@ -19,9 +19,9 @@ package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl;
 import java.io.File;
 import java.util.List;
 
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.BasicDataSetInformation;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.BasicDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetStructure.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetStructure.java
index 89b839f83334e8abf2e07b471e5e5e69a054aba7..d9a2e08f15fc92a6cb4387dcdcde7a2bc713221c 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetStructure.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetStructure.java
@@ -21,11 +21,11 @@ import java.util.List;
 
 import ch.systemsx.cisd.common.collection.CollectionUtils;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageStorageConfiguraton;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageStorageConfiguraton;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ToStringUtil;
 
 /**
@@ -36,7 +36,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ToStringUtil;
  */
 public class ImageDataSetStructure implements Serializable
 {
-    
+
     private static final long serialVersionUID = 1L;
 
     private List<ImageFileInfo> images;
@@ -122,8 +122,12 @@ public class ImageDataSetStructure implements Serializable
             throw new IllegalArgumentException(
                     "There should be exactly one color component for each channel!");
         }
+
         this.channels = channels;
-        this.channelColorComponentsOrNull = channelColorComponents;
+        // potentially necessary conversion of v1 ChanelColorComponent
+        this.channelColorComponentsOrNull =
+                ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent
+                        .convertToIndependentChannelColorList(channelColorComponents);
     }
 
     /**
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ThumbnailsInfo.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ThumbnailsInfo.java
index 6c3c8c3f44466f29193d20c0b06c32f5cedb1a2d..18c79fc21fa5526dfbf43ed4b015d7773882210c 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ThumbnailsInfo.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ThumbnailsInfo.java
@@ -6,7 +6,7 @@ import java.util.Map;
 import java.util.Set;
 
 import ch.systemsx.cisd.openbis.dss.etl.dto.RelativeImageFile;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat.FileFormat;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat.FileFormat;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ToStringUtil;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/AbstractThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/AbstractThumbnailsConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc300d2c7e04174e4dbcd8e205b0eeacda802940
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/AbstractThumbnailsConfiguration.java
@@ -0,0 +1,112 @@
+/*
+ * 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.dss.etl.dto.api.thumbnails;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public abstract class AbstractThumbnailsConfiguration implements IThumbnailsConfiguration
+{
+    private String fileName;
+
+    private String fileFormat;
+
+    private Map<String, String> transformations = new HashMap<String, String>();
+
+    @Override
+    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config)
+    {
+        ThumbnailsStorageFormat thumbnailsStorageFormat = new ThumbnailsStorageFormat();
+        thumbnailsStorageFormat.setAllowedMachineLoadDuringGeneration(config
+                .getAllowedMachineLoadDuringThumbnailsGeneration());
+        thumbnailsStorageFormat.setThumbnailsFileName(getFileName());
+        thumbnailsStorageFormat.setMaxWidth(config.getMaxThumbnailWidthAndHeight());
+        thumbnailsStorageFormat.setMaxHeight(config.getMaxThumbnailWidthAndHeight());
+        thumbnailsStorageFormat.setGenerateWithImageMagic(config
+                .getGenerateThumbnailsWithImageMagic());
+        thumbnailsStorageFormat.setImageMagicParams(config
+                .getThumbnailsGenerationImageMagicParams());
+        thumbnailsStorageFormat.setHighQuality(config.getGenerateThumbnailsIn8BitHighQuality());
+        setFileFormat(thumbnailsStorageFormat, config.getThumbnailsFileFormat());
+        thumbnailsStorageFormat.setTransformations(transformations);
+        return thumbnailsStorageFormat;
+    }
+
+    protected abstract String getDefaultFileName();
+
+    @Override
+    public void setFileName(String fileName)
+    {
+        this.fileName = fileName;
+    }
+
+    public String getFileName()
+    {
+        if (fileName != null)
+        {
+            return fileName;
+        } else
+        {
+            return getDefaultFileName();
+        }
+    }
+
+    @Override
+    public void setFileFormat(String fileFormat)
+    {
+        this.fileFormat = fileFormat;
+    }
+
+    public String getFileFormat()
+    {
+        return this.fileFormat;
+    }
+
+    private void setFileFormat(ThumbnailsStorageFormat thumbnailsStorageFormat, String defaultValue)
+    {
+        if (fileFormat != null)
+        {
+            thumbnailsStorageFormat.setFileFormat(fileFormat);
+        } else if (defaultValue != null)
+        {
+            thumbnailsStorageFormat.setFileFormat(defaultValue);
+        }
+    }
+
+    @Override
+    public String setTransformation(String channelCode, String transformationCode)
+    {
+        return transformations.put(channelCode.toUpperCase(), transformationCode);
+    }
+
+    protected String getFirstTransformationCode()
+    {
+        if (transformations.size() == 0)
+        {
+            return "";
+        } else
+        {
+            return "_" + transformations.values().iterator().next();
+        }
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/DefaultThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/DefaultThumbnailsConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..689e4b706539b081053de60efdaae0b2c3f92f0e
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/DefaultThumbnailsConfiguration.java
@@ -0,0 +1,31 @@
+/*
+ * 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.dss.etl.dto.api.thumbnails;
+
+import ch.systemsx.cisd.openbis.dss.Constants;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class DefaultThumbnailsConfiguration extends AbstractThumbnailsConfiguration
+{
+    @Override
+    protected String getDefaultFileName()
+    {
+        return Constants.HDF5_CONTAINER_THUMBNAILS_FILE_NAME;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/IThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/IThumbnailsConfiguration.java
similarity index 87%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/IThumbnailsConfiguration.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/IThumbnailsConfiguration.java
index a4e23c1781ec507ff71d90a47be337a4dee3c698..87a2655c0ac8706de57e2cefd6da3cb080fe9382 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/IThumbnailsConfiguration.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/IThumbnailsConfiguration.java
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails;
 
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
 
 /**
  * @author Pawel Glyzewski
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/ResolutionBasedThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/ResolutionBasedThumbnailsConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc0d16c563314489d520da6be79c0f04bb47fd5c
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/ResolutionBasedThumbnailsConfiguration.java
@@ -0,0 +1,62 @@
+/*
+ * 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.dss.etl.dto.api.thumbnails;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class ResolutionBasedThumbnailsConfiguration extends AbstractThumbnailsConfiguration
+{
+    private final int maxWidth;
+
+    private final int maxHeight;
+
+    private final boolean allowEnlarging;
+
+    public ResolutionBasedThumbnailsConfiguration(int maxWidth, int maxHeight)
+    {
+        this(maxWidth, maxHeight, true);
+    }
+
+    public ResolutionBasedThumbnailsConfiguration(int maxWidth, int maxHeight,
+            boolean allowEnlarging)
+    {
+        this.maxWidth = maxWidth;
+        this.maxHeight = maxHeight;
+        this.allowEnlarging = allowEnlarging;
+    }
+
+    @Override
+    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config)
+    {
+        ThumbnailsStorageFormat thumbnailsStorageFormat = super.getThumbnailsStorageFormat(config);
+        thumbnailsStorageFormat.setMaxWidth(maxWidth);
+        thumbnailsStorageFormat.setMaxHeight(maxHeight);
+        thumbnailsStorageFormat.setAllowEnlarging(allowEnlarging);
+        return thumbnailsStorageFormat;
+    }
+
+    @Override
+    protected String getDefaultFileName()
+    {
+        return String.format("thumbnails_%dx%d%s.h5ar", maxWidth, maxHeight,
+                getFirstTransformationCode());
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e96d5c83c34ba996fb85700ff7d01e6a1653ecf
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java
@@ -0,0 +1,48 @@
+/*
+ * 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.dss.etl.dto.api.thumbnails;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class ZoomLevelBasedThumbnailsConfiguration extends AbstractThumbnailsConfiguration
+{
+    private final double zoomLevel;
+
+    public ZoomLevelBasedThumbnailsConfiguration(double zoomLevel)
+    {
+        this.zoomLevel = zoomLevel;
+    }
+
+    @Override
+    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config)
+    {
+        ThumbnailsStorageFormat thumbnailsStorageFormat = super.getThumbnailsStorageFormat(config);
+        thumbnailsStorageFormat.setZoomLevel(zoomLevel);
+        return thumbnailsStorageFormat;
+    }
+
+    @Override
+    protected String getDefaultFileName()
+    {
+        return String.format("thumbnails_%.0fpct%s.h5ar", zoomLevel * 100.0,
+                getFirstTransformationCode());
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/AutoRescaleIntensityImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/AutoRescaleIntensityImageTransformerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..97a16508fa1d5889151b569b7280a5e22bcc99f0
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/AutoRescaleIntensityImageTransformerFactory.java
@@ -0,0 +1,69 @@
+/*
+ * 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.dss.etl.dto.api.transformations;
+
+import java.awt.image.BufferedImage;
+
+
+import ch.systemsx.cisd.base.image.IImageTransformer;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.base.annotation.JsonObject;
+import ch.systemsx.cisd.common.image.IntensityRescaling;
+import ch.systemsx.cisd.common.image.IntensityRescaling.Levels;
+
+/**
+ * Transformation performed by
+ * {@link IntensityRescaling#rescaleIntensityLevelTo8Bits(BufferedImage, Levels)} where levels are
+ * computed automatically by {@link IntensityRescaling#computeLevels(BufferedImage, float)}.
+ * <p>
+ * Warning: The serialized version of this class can be stored in the database for each image.
+ * Moving this class to a different package or changing it in a backward incompatible way would make
+ * all the saved transformations invalid.
+ * 
+ * @author Tomasz Pylak
+ */
+@JsonObject("AutoRescaleIntensityImageTransformerFactory")
+public class AutoRescaleIntensityImageTransformerFactory implements IImageTransformerFactory
+{
+    private static final long serialVersionUID = 1L;
+
+    private final float threshold;
+
+    public AutoRescaleIntensityImageTransformerFactory(float threshold)
+    {
+        this.threshold = threshold;
+    }
+
+    @Override
+    public IImageTransformer createTransformer()
+    {
+        return new IImageTransformer()
+            {
+                @Override
+                public BufferedImage transform(BufferedImage image)
+                {
+                    if (IntensityRescaling.isNotGrayscale(image))
+                    {
+                        return image;
+                    }
+                    Levels levels = IntensityRescaling.computeLevels(image, threshold);
+                    return IntensityRescaling.rescaleIntensityLevelTo8Bits(image, levels);
+                }
+            };
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/BitShiftingImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/BitShiftingImageTransformerFactory.java
similarity index 95%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/BitShiftingImageTransformerFactory.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/BitShiftingImageTransformerFactory.java
index 1209dc120ac0d3d86637977cc6247a90bc6fa951..5917b60a0cccfb203e84d975e8fece7aa15bae45 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/BitShiftingImageTransformerFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/BitShiftingImageTransformerFactory.java
@@ -1,11 +1,10 @@
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations;
 
 import java.awt.image.BufferedImage;
 
-
+import ch.systemsx.cisd.base.annotation.JsonObject;
 import ch.systemsx.cisd.base.image.IImageTransformer;
 import ch.systemsx.cisd.base.image.IImageTransformerFactory;
-import ch.systemsx.cisd.base.annotation.JsonObject;
 import ch.systemsx.cisd.common.image.IntensityRescaling;
 
 /**
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformer.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformer.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c061da84106894e4e64e2ee581ba8de67016789
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformer.java
@@ -0,0 +1,269 @@
+/*
+ * 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.dss.etl.dto.api.transformations;
+
+import java.awt.image.BufferedImage;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.image.IStreamingImageTransformer;
+import ch.systemsx.cisd.base.utilities.OSUtilities;
+import ch.systemsx.cisd.common.concurrent.ConcurrencyUtilities;
+import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.process.IProcessIOHandler;
+import ch.systemsx.cisd.common.process.ProcessExecutionHelper;
+import ch.systemsx.cisd.common.process.ProcessIOStrategy;
+import ch.systemsx.cisd.common.process.ProcessResult;
+import ch.systemsx.cisd.imagereaders.IImageReader;
+import ch.systemsx.cisd.imagereaders.ImageID;
+import ch.systemsx.cisd.imagereaders.ImageReaderConstants;
+import ch.systemsx.cisd.imagereaders.ImageReaderFactory;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ConvertToolImageTransformerFactory.ToolChoice;
+import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
+
+/**
+ * An {@link IStreamingImageTransformer} using the convert command line tool for transformations.
+ * 
+ * @author Kaloyan Enimanev
+ */
+public class ConvertToolImageTransformer implements IStreamingImageTransformer
+{
+
+    private static final String PNG = "png";
+
+    private static final File imageMagickConvertUtilityOrNull;
+
+    private static final File graphicsMagickUtilityOrNull;
+
+    static
+    {
+        imageMagickConvertUtilityOrNull = OSUtilities.findExecutable("convert");
+        graphicsMagickUtilityOrNull = OSUtilities.findExecutable("gm");
+        if (imageMagickConvertUtilityOrNull == null && graphicsMagickUtilityOrNull == null)
+        {
+            throw new ConfigurationFailureException(
+                    "Neither ImageMagick 'convert' nor GraphisMagick 'gm' can be found"
+                            + " on the system path. Requested image transformation is not available.");
+        }
+    }
+
+    private static final Logger machineLog = LogFactory.getLogger(LogCategory.MACHINE,
+            ConvertToolImageTransformer.class);
+
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            ConvertToolImageTransformer.class);
+
+    private final byte[] buffer = new byte[ProcessExecutionHelper.RECOMMENDED_BUFFER_SIZE];
+
+    private final List<String> convertCliArguments;
+
+    private final boolean useGraphicsMagic;
+
+    protected ConvertToolImageTransformer(String arguments, ToolChoice choiceOrNull)
+    {
+        this.convertCliArguments = parseCommandArguments(arguments);
+        ToolChoice choice = (choiceOrNull == null ? ToolChoice.ENFORCE_IMAGEMAGICK : choiceOrNull);
+        switch (choice)
+        {
+            case ENFORCE_IMAGEMAGICK:
+                if (imageMagickConvertUtilityOrNull == null)
+                {
+                    throw new ConfigurationFailureException(
+                            "The ImageMagick 'convert' tool cannot be found on the system path."
+                                    + " Requested image transformation is not available.");
+                }
+                useGraphicsMagic = false;
+                break;
+            case ENFORCE_GRAPHICSMAGICK:
+                if (graphicsMagickUtilityOrNull == null)
+                {
+                    throw new ConfigurationFailureException(
+                            "The GraphicsMagic 'gm' tool cannot be found on the system path."
+                                    + " Requested image transformation is not available.");
+                }
+                useGraphicsMagic = true;
+                break;
+            case PREFER_IMAGEMAGICK:
+                useGraphicsMagic = (imageMagickConvertUtilityOrNull == null);
+                break;
+            case PREFER_GRAPHICSMAGICK:
+                useGraphicsMagic = (graphicsMagickUtilityOrNull != null);
+                break;
+            default:
+                throw new Error("Unknown ToolChoice " + choice + ".");
+        }
+    }
+
+    @Override
+    public BufferedImage transform(BufferedImage image)
+    {
+        try
+        {
+            byte[] input = ImageUtil.imageToPngFast(image);
+            byte[] output = transform(input);
+            return toBufferedImage(output);
+        } catch (IOException ioex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ioex);
+        }
+    }
+
+    @Override
+    public BufferedImage transform(InputStream input)
+    {
+        return toBufferedImage(transformToPNG(input));
+    }
+
+    @Override
+    public byte[] transformToPNG(InputStream input)
+    {
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        transformToPNGStream(input, bos);
+        return bos.toByteArray();
+    }
+
+    @Override
+    public void transformToPNGStream(InputStream input, OutputStream output)
+    {
+        try
+        {
+            transform(input, output);
+        } catch (IOException ioex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ioex);
+        }
+    }
+
+    private BufferedImage toBufferedImage(byte[] output) throws ConfigurationFailureException
+    {
+        IImageReader imageReader =
+                ImageReaderFactory.tryGetReader(ImageReaderConstants.IMAGEIO_LIBRARY, PNG);
+        if (imageReader == null)
+        {
+            throw new ConfigurationFailureException("No ImageIO image readers available");
+        }
+        return imageReader.readImage(output, ImageID.NULL, null);
+    }
+
+    private byte[] transform(final byte[] input) throws IOException
+    {
+        final ByteArrayInputStream bis = new ByteArrayInputStream(input);
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        transform(bis, bos);
+        return bos.toByteArray();
+    }
+
+    private void transform(final InputStream input, final OutputStream output) throws IOException
+    {
+
+        final List<String> errorLines = new ArrayList<String>();
+        ProcessIOStrategy customIOStrategy =
+                createCustomProcessIOStrategy(input, output, errorLines);
+
+        ProcessResult result =
+                ProcessExecutionHelper.run(getCommandLine(), operationLog, machineLog,
+                        ConcurrencyUtilities.NO_TIMEOUT, customIOStrategy, false);
+
+        if (result.isOK() == false)
+        {
+            final String msg =
+                    String.format(
+                            "Error calling '%s'. Exit value: %d, I/O status: %s\nError output: %s",
+                            getCommandLine().toString(), result.getExitValue(), result
+                                    .getProcessIOResult().getStatus(), errorLines.toString());
+            operationLog.warn(msg);
+            throw new IOException(msg);
+        }
+    }
+
+    private ProcessIOStrategy createCustomProcessIOStrategy(final InputStream input,
+            final OutputStream output, final List<String> errorLines)
+    {
+        return ProcessIOStrategy.createCustom(new IProcessIOHandler()
+            {
+
+                @Override
+                public void handle(AtomicBoolean processRunning, OutputStream stdin,
+                        InputStream stdout, InputStream stderr) throws IOException
+                {
+                    int n = 0;
+                    final BufferedReader stdErrReader =
+                            new BufferedReader(new InputStreamReader(stderr));
+                    while (processRunning.get() && (-1 != (n = input.read(buffer))))
+                    {
+                        stdin.write(buffer, 0, n);
+                        ProcessExecutionHelper.readBytesIfAvailable(stdout, output, buffer, -1,
+                                false);
+                        ProcessExecutionHelper.readTextIfAvailable(stdErrReader, errorLines, false);
+                    }
+                    stdin.flush();
+                    stdin.close();
+
+                    while (processRunning.get())
+                    {
+                        ProcessExecutionHelper.readBytesIfAvailable(stdout, output, buffer, -1,
+                                false);
+                        ProcessExecutionHelper.readTextIfAvailable(stdErrReader, errorLines, false);
+                    }
+
+                    ProcessExecutionHelper.readBytesIfAvailable(stdout, output, buffer, -1, false);
+                    ProcessExecutionHelper.readTextIfAvailable(stdErrReader, errorLines, false);
+                }
+            });
+    }
+
+    private List<String> parseCommandArguments(String argsString)
+    {
+        String[] arguments = argsString.trim().split("\\s");
+        return Arrays.asList(arguments);
+    }
+
+    private List<String> getCommandLine()
+    {
+        ArrayList<String> result = new ArrayList<String>();
+        if (useGraphicsMagic)
+        {
+            result.add(graphicsMagickUtilityOrNull.getPath());
+            result.add("convert");
+        } else
+        {
+            result.add(imageMagickConvertUtilityOrNull.getPath());
+        }
+        result.addAll(convertCliArguments);
+        // use standard input to read image
+        result.add("-");
+        // use standard output to produce result
+        result.add("png:-");
+        return result;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..df3e6e75f22ccbce3b00565312ca44c7e5b7ec6a
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformerFactory.java
@@ -0,0 +1,68 @@
+/*
+ * 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.dss.etl.dto.api.transformations;
+
+import ch.systemsx.cisd.base.image.IStreamingImageTransformerFactory;
+
+/**
+ * A {@link IStreamingImageTransformerFactory} that constructs {@link ConvertToolImageTransformer}
+ * instances.
+ * <p>
+ * Warning: The serialized version of this class can be stored in the database for each image.
+ * Moving this class to a different package or changing it in a backward incompatible way would make
+ * all the saved transformations invalid.
+ * 
+ * @author Kaloyan Enimanev
+ */
+public class ConvertToolImageTransformerFactory implements IStreamingImageTransformerFactory
+{
+    private static final long serialVersionUID = 1L;
+
+    private final String convertCliArguments;
+
+    private final ToolChoice choice;
+
+    /**
+     * An enum to choose which of the two tools, ImageMagick or GraphicsMagick, to prefer or to
+     * enforce.
+     */
+    public enum ToolChoice
+    {
+        ENFORCE_IMAGEMAGICK, ENFORCE_GRAPHICSMAGICK, PREFER_IMAGEMAGICK, PREFER_GRAPHICSMAGICK
+    }
+
+    /**
+     * Constructs the factory with {@link ToolChoice#PREFER_IMAGEMAGICK}.
+     */
+    public ConvertToolImageTransformerFactory(String convertCliArguments)
+    {
+        this(convertCliArguments, ToolChoice.ENFORCE_IMAGEMAGICK);
+    }
+
+    public ConvertToolImageTransformerFactory(String convertCliArguments, ToolChoice choice)
+    {
+        this.convertCliArguments = convertCliArguments;
+        this.choice = choice;
+    }
+
+    @Override
+    public ConvertToolImageTransformer createTransformer()
+    {
+        return new ConvertToolImageTransformer(convertCliArguments, choice);
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformation.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformation.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9d41ef5b5839e6be5b4483ef48229df19fbd36e
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformation.java
@@ -0,0 +1,139 @@
+/*
+ * 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.dss.etl.dto.api.transformations;
+
+import java.io.Serializable;
+
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
+
+/**
+ * Describes image transformation, contains user friendly label and description.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ImageTransformation implements Serializable
+{
+    
+    private static final long serialVersionUID = 1L;
+
+    private String code;
+
+    private String label;
+
+    // can be null
+    private String description;
+
+    private boolean isDefault;
+
+    private final IImageTransformerFactory imageTransformerFactory;
+
+    private final boolean isEditable;
+
+    public ImageTransformation(String code, String label, String description,
+            IImageTransformerFactory imageTransformerFactory)
+    {
+        assert code != null : "code is null";
+        assert label != null : " label is null";
+        assert imageTransformerFactory != null : "imageTransformerFactory is null";
+
+        this.code = CodeNormalizer.normalize(code);
+        this.label = label;
+        this.description = description;
+        this.isDefault = false;
+        this.imageTransformerFactory = imageTransformerFactory;
+        this.isEditable = false; // will be used later for ImageViewer transformations
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public String getLabel()
+    {
+        return label;
+    }
+
+    public String getDescription()
+    {
+        return description;
+    }
+
+    public boolean isDefault()
+    {
+        return isDefault;
+    }
+
+    public IImageTransformerFactory getImageTransformerFactory()
+    {
+        return imageTransformerFactory;
+    }
+
+    public boolean isEditable()
+    {
+        return isEditable;
+    }
+
+    // ----------- setters
+
+    public void setCode(String code)
+    {
+        this.code = code;
+    }
+
+    public void setLabel(String label)
+    {
+        this.label = label;
+    }
+
+    public void setDescription(String description)
+    {
+        this.description = description;
+    }
+
+    /**
+     * Calling with true makes this transformation a default user's choice and makes the
+     * 'hard-coded' default unavailable. This transformation will become the first one on the list
+     * automatically.
+     * <p>
+     * Marking more then one transformation as a default for one channel will make it impossible to
+     * register a dataset.
+     * </p>
+     * <p>
+     * If no transformation on the list will be marked as default then a 'hard-coded' default
+     * transformation will become available.
+     * </p>
+     */
+    public void setDefault(boolean isDefault)
+    {
+        this.isDefault = isDefault;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append("ImageTransformation [code=" + code + ", label=" + label);
+        if (description != null)
+        {
+            sb.append(", description=" + description);
+        }
+        sb.append(", isDefault=" + isDefault + "]");
+        return sb.toString();
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformationBuffer.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformationBuffer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ec4f470f3b12c9a31dfeb92e417e8bc3164605b
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformationBuffer.java
@@ -0,0 +1,465 @@
+/*
+ * 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.dss.etl.dto.api.transformations;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
+import ch.systemsx.cisd.common.shared.basic.string.StringUtils;
+
+/**
+ * Utility class to construct various kinds of image transformations.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ImageTransformationBuffer
+{
+    private static final String PREDEFINED_TRANSFORMATIONS_CODE_PREFIX = "_";
+
+    private final List<ImageTransformation> imageTransformations;
+
+    public ImageTransformationBuffer()
+    {
+        this.imageTransformations = new ArrayList<ImageTransformation>();
+    }
+
+    /**
+     * Appends a single transformation and returns it. Note that code of each added transformation
+     * should be unique.
+     */
+    public ImageTransformation append(ImageTransformation transformation)
+    {
+        appendAll(transformation);
+        return transformation;
+    }
+
+    /**
+     * Appends any specified transformations. Note that code of each added transformation should be
+     * unique.
+     */
+    public void appendAll(ImageTransformation... transformations)
+    {
+        for (ImageTransformation transformation : transformations)
+        {
+            imageTransformations.add(transformation);
+        }
+        ensureTransformationCodesUnique();
+    }
+
+    // returns a set of used transformation codes
+    private Set<String> ensureTransformationCodesUnique()
+    {
+        Set<String> usedTransformationCodes = new HashSet<String>();
+        for (ImageTransformation transformation : imageTransformations)
+        {
+            String code = transformation.getCode();
+            if (usedTransformationCodes.contains(code))
+            {
+                throw new IllegalArgumentException("Two transformations have the same code: "
+                        + code);
+            }
+            usedTransformationCodes.add(code);
+        }
+        return usedTransformationCodes;
+    }
+
+    private void ensureOnlyOneDefault()
+    {
+        ImageTransformation defaultTansf = null;
+        for (ImageTransformation transformation : imageTransformations)
+        {
+            if (transformation.isDefault())
+            {
+                if (defaultTansf == null)
+                {
+                    defaultTansf = transformation;
+                } else
+                {
+                    throw ConfigurationFailureException.fromTemplate(
+                            "Only one image transformation can be default, but two were found: '%s' and "
+                                    + "'%s'.", defaultTansf.getLabel(), transformation.getLabel());
+                }
+            }
+        }
+    }
+
+    /** @returns all appended transformations */
+    public ImageTransformation[] getTransformations()
+    {
+        // codes of transformations could be changed after they have been added
+        ensureTransformationCodesUnique();
+        ensureOnlyOneDefault();
+        return imageTransformations.toArray(new ImageTransformation[imageTransformations.size()]);
+    }
+
+    // -------------- bit shifting transformations ---------------------
+
+    /**
+     * Appends transformations which extracts a range of grayscale image colors by choosing 8
+     * consecutive bits. All shifts which make sense for 12 bit images will be appended (from 0 to
+     * 4).
+     * 
+     * @return appended transformations. They can be used to e.g. modify their label or description.
+     */
+    public ImageTransformation[] appendAllBitShiftsFor12BitGrayscale()
+    {
+        return appendAllAvailableGrayscaleBitShifts(12);
+    }
+
+    /**
+     * Appends transformations which extracts a range of grayscale image colors by choosing 8
+     * consecutive bits. All shifts which make sense for 16 bit images will be appended (from 0 to
+     * 8).
+     * 
+     * @return appended transformations. They can be used to e.g. modify their label or description.
+     */
+    public ImageTransformation[] appendAllBitShiftsFor16BitGrayscale()
+    {
+        return appendAllAvailableGrayscaleBitShifts(16);
+    }
+
+    private ImageTransformation[] appendAllAvailableGrayscaleBitShifts(int totalNumberOfBits)
+    {
+        int transformationsNumber = totalNumberOfBits - 8 + 1;
+        ImageTransformation[] transformations = new ImageTransformation[transformationsNumber];
+        for (int i = 0; i < transformationsNumber; i++)
+        {
+            transformations[i] = appendGrayscaleBitShifting(i);
+        }
+        return transformations;
+    }
+
+    /**
+     * Appends transformation which extracts a range of grayscale image colors by choosing 8
+     * consecutive bits starting from the specified one.
+     * 
+     * @return appended transformation. It can be used to e.g. modify its label or description.
+     */
+    public ImageTransformation appendGrayscaleBitShifting(int shiftBits)
+    {
+        return append(createGrayscaleBitShifting(shiftBits));
+    }
+
+    /**
+     * Creates a transformation which extracts a range of grayscale image colors by choosing 8
+     * consecutive bits, staring from the specified one.
+     * <p>
+     * This method is useful when one wants to modify the default code, label or description
+     * afterwards.
+     */
+    private static ImageTransformation createGrayscaleBitShifting(int shiftBits)
+    {
+        if (shiftBits < 0)
+        {
+            throw new IllegalArgumentException(
+                    "Cannot create an image transformation which shifts by a negative number of bits");
+        }
+        String label = createBitShiftingTransformationLabel(shiftBits);
+        String code = createBitShiftingTransformationCode(shiftBits);
+        String description = createBitShiftingTransformationDescription(shiftBits);
+
+        IImageTransformerFactory factory = new BitShiftingImageTransformerFactory(shiftBits);
+        return new ImageTransformation(code, label, description, factory);
+    }
+
+    private static String createBitShiftingTransformationCode(int shiftBits)
+    {
+        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "BIT_SHIFTING_" + shiftBits;
+    }
+
+    private static String createBitShiftingTransformationDescription(int shiftBits)
+    {
+        return String.format(
+                "Shows a range of grayscale image colors by visualising only 8 consecutive bits from %d to %d. "
+                        + "Useful for extracting information from 12 and 16 bit images.",
+                shiftBits, shiftBits + 7);
+    }
+
+    private static String createBitShiftingTransformationLabel(int shiftBits)
+    {
+        return String.format("Show bits %d-%d", shiftBits, shiftBits + 7);
+    }
+
+    // -----------------------------
+
+    /**
+     * Appends transformation which converts grayscale image pixel intensities from the range
+     * [blackPointIntensity, whitePointIntensity] to 8 bit color depth. Useful to compare images of
+     * higher color depth with each other when they do not use the whole range of available
+     * intensities.
+     * 
+     * @return appended transformation. It can be used to e.g. modify its label or description.
+     */
+    public ImageTransformation appendRescaleGrayscaleIntensity(int blackPointIntensity,
+            int whitePointIntensity)
+    {
+        return appendRescaleGrayscaleIntensity(blackPointIntensity, whitePointIntensity, null);
+    }
+
+    /**
+     * See {@link #appendRescaleGrayscaleIntensity(int, int)}.
+     * <p>
+     * Additionally sets the label of the transformation.
+     * 
+     * @return appended transformation. It can be used to e.g. modify its label or description.
+     */
+    public ImageTransformation appendRescaleGrayscaleIntensity(int blackPointIntensity,
+            int whitePointIntensity, String userFriendlyLabelOrNull)
+    {
+        return append(createRescaleGrayscaleIntensity(blackPointIntensity, whitePointIntensity,
+                userFriendlyLabelOrNull));
+    }
+
+    /**
+     * Creates a transformation which converts grayscale image pixel intensities from the range
+     * [blackPointIntensity, whitePointIntensity] to 8 bit color depth.
+     * <p>
+     * This method is useful when one wants to modify the default code, label or description
+     * afterwards.
+     * 
+     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
+     *            assigned.
+     */
+    public static ImageTransformation createRescaleGrayscaleIntensity(int blackPointIntensity,
+            int whitePointIntensity, String userFriendlyLabelOrNull)
+    {
+        if (blackPointIntensity > whitePointIntensity || blackPointIntensity < 0
+                || whitePointIntensity < 0)
+        {
+            throw new IllegalArgumentException(String.format(
+                    "Cannot create an image transformation because the range "
+                            + "of intensities is invalid: [%d, %d]", blackPointIntensity,
+                    whitePointIntensity));
+        }
+        String label = createIntensityRangeTransformationLabel(userFriendlyLabelOrNull);
+        String code =
+                createIntensityRangeTransformationCode(blackPointIntensity, whitePointIntensity);
+        String description =
+                createIntensityRangeTransformationDescription(blackPointIntensity,
+                        whitePointIntensity);
+
+        IImageTransformerFactory factory =
+                new IntensityRangeImageTransformerFactory(blackPointIntensity, whitePointIntensity);
+        return new ImageTransformation(code, label, description, factory);
+    }
+
+    private static String createIntensityRangeTransformationCode(int blackPointIntensity,
+            int whitePointIntensity)
+    {
+        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "INTENSITY_LEVEL_" + blackPointIntensity
+                + "_" + whitePointIntensity;
+    }
+
+    private static String createIntensityRangeTransformationDescription(int blackPointIntensity,
+            int whitePointIntensity)
+    {
+        return String
+                .format("Transforms grayscale image by converting intensities of its pixels "
+                        + "which are in the range [%d, %d] to 8 bit color depth. "
+                        + "The range of intensities is usually calculated by processing a series of 12 or 16 bit images, "
+                        + "then the transformation becomes useful to compare these images with each other in 8 bit color depth, "
+                        + "especially when they use only a small part of available intensities range.",
+                        blackPointIntensity, whitePointIntensity);
+    }
+
+    private static String createIntensityRangeTransformationLabel(String labelOrNull)
+    {
+        return labelOrNull != null ? labelOrNull : "Fixed rescaling";
+    }
+
+    // --------------------------
+
+    /**
+     * Appends transformation which converts each single grayscale image to 8 bit color depth and
+     * rescales pixels intensities so that the darkest pixel will become black and the brightest
+     * will become white.
+     * <p>
+     * Note that by default openBIS applies this transformation with threshold 0 if it deals with
+     * grayscale image where color depth is bigger then 8 bit. So calling this method with parameter
+     * 0 is not necessary.
+     * </p>
+     * 
+     * @param threshold value form 0 to 1, it specifies the percentage of darkest and brightest
+     *            pixels which will be ignored (they will all become black or white).
+     * @return appended transformation. It can be used to e.g. modify its label or description.
+     */
+    public ImageTransformation appendAutoRescaleGrayscaleIntensity(float threshold)
+    {
+        return appendAutoRescaleGrayscaleIntensity(threshold, null);
+    }
+
+    /**
+     * See {@link #appendAutoRescaleGrayscaleIntensity(float)}.
+     * <p>
+     * Additionally sets the label of the transformation.
+     * 
+     * @return appended transformation. It can be used to e.g. modify its label or description.
+     */
+    public ImageTransformation appendAutoRescaleGrayscaleIntensity(float threshold,
+            String userFriendlyLabelOrNull)
+    {
+        return append(createAutoRescaleGrayscaleIntensity(threshold, userFriendlyLabelOrNull));
+    }
+
+    /**
+     * Creates a transformation which converts each single grayscale image to 8 bit color depth and
+     * rescales pixels intensities so that the darkest pixel will become black and the brightest
+     * will become white (with some threshold margin).
+     * <p>
+     * This method is useful when one wants to modify the default code, label or description
+     * afterwards.
+     * 
+     * @param threshold value form 0 to 1, it specifies the percentage of darkest and brightest
+     *            pixels which will be ignored (they will all become black or white).
+     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
+     *            assigned.
+     */
+    private static ImageTransformation createAutoRescaleGrayscaleIntensity(float threshold,
+            String userFriendlyLabelOrNull)
+    {
+        if (threshold < 0 || threshold > 1)
+        {
+            throw new IllegalArgumentException(
+                    "Invalid value of the threshold, should be between 0 and 1, but is: "
+                            + threshold);
+        }
+        String label =
+                createAutoRescaleIntensityTransformationLabel(userFriendlyLabelOrNull, threshold);
+        String code = createAutoRescaleIntensityTransformationCode(threshold);
+        String description = createAutoRescaleIntensityTransformationDescription(threshold);
+
+        IImageTransformerFactory factory =
+                new AutoRescaleIntensityImageTransformerFactory(threshold);
+        return new ImageTransformation(code, label, description, factory);
+    }
+
+    private static String createAutoRescaleIntensityTransformationCode(float threshold)
+    {
+        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "AUTO_INTENSITY_LEVEL_" + (threshold * 100);
+    }
+
+    private static String createAutoRescaleIntensityTransformationDescription(float threshold)
+    {
+        return String
+                .format("Creates a transformation which converts each single grayscale image to 8 bit color depth and "
+                        + "rescales pixels intensities so that the darkest pixel will become black and the brightest "
+                        + "will become white (threshold margin: %s).",
+                        new DecimalFormat("#.###").format(threshold));
+    }
+
+    @Private
+    static String createAutoRescaleIntensityTransformationLabel(String labelOrNull, float threshold)
+    {
+        String thresholdPercentage = new DecimalFormat("##.#").format(threshold * 100);
+        return labelOrNull != null ? labelOrNull : String.format("Optimal (image, %s%% cut)",
+                thresholdPercentage);
+    }
+
+    // --------------------------
+
+    /**
+     * Allows to transform the images with ImageMagic convert tool (which has to be installed and
+     * accessible). Convert will be called with the specified parameters.
+     * 
+     * @return appended transformation. It can be used to e.g. modify its label or description.
+     */
+    public ImageTransformation appendImageMagicConvert(String convertCliArguments)
+    {
+        return appendImageMagicConvert(convertCliArguments, null);
+    }
+
+    /**
+     * See {@link #appendImageMagicConvert(String)}.
+     * <p>
+     * Additionally sets the label of the transformation.
+     * 
+     * @return appended transformation. It can be used to e.g. modify its label or description.
+     */
+    public ImageTransformation appendImageMagicConvert(String convertCliArguments,
+            String userFriendlyLabelOrNull)
+    {
+        return append(createImageMagicConvert(convertCliArguments,
+                generateUniqueConvertTransformationCode(), userFriendlyLabelOrNull));
+    }
+
+    /**
+     * Creates a transformation which converts the images with ImageMagic convert tool.
+     * <p>
+     * This method is useful when one wants to modify the default code, label or description
+     * afterwards.
+     * 
+     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
+     *            assigned.
+     */
+    private static ImageTransformation createImageMagicConvert(String convertCliArguments,
+            String transformationCode, String userFriendlyLabelOrNull)
+    {
+        if (StringUtils.isBlank(convertCliArguments))
+        {
+            throw new IllegalArgumentException(
+                    "No argument has been specified for the 'convert' command");
+        }
+        if (StringUtils.isBlank(transformationCode))
+        {
+            throw new IllegalArgumentException("Transformation has not been specified");
+        }
+        String label =
+                createImageMagicConvertTransformationLabel(convertCliArguments,
+                        userFriendlyLabelOrNull);
+        String description = createImageMagicConvertTransformationDescription(convertCliArguments);
+
+        IImageTransformerFactory factory =
+                new ConvertToolImageTransformerFactory(convertCliArguments);
+        return new ImageTransformation(transformationCode, label, description, factory);
+    }
+
+    private static String createImageMagicConvertTransformationDescription(
+            String convertCliArguments)
+    {
+        return String.format("Transforms images with ImageMagic tool by calling: 'convert %s ...'",
+                convertCliArguments);
+    }
+
+    private static String createImageMagicConvertTransformationLabel(String convertCliArguments,
+            String labelOrNull)
+    {
+        return labelOrNull != null ? labelOrNull : String.format("Convert (%s)",
+                convertCliArguments);
+    }
+
+    private String generateUniqueConvertTransformationCode()
+    {
+        int i = 1;
+        Set<String> usedTransformationCodes = ensureTransformationCodesUnique();
+        while (usedTransformationCodes.contains(getConvertTransformationCode(i)))
+        {
+            i++;
+        }
+        return getConvertTransformationCode(i);
+    }
+
+    private static String getConvertTransformationCode(int seqNumber)
+    {
+        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "CONVERT_" + seqNumber;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/IntensityRangeImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/IntensityRangeImageTransformerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..abae0a567e4596951435e42cf330d206290e1547
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/IntensityRangeImageTransformerFactory.java
@@ -0,0 +1,82 @@
+/*
+ * 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.dss.etl.dto.api.transformations;
+
+import java.awt.image.BufferedImage;
+
+
+import ch.systemsx.cisd.base.image.IImageTransformer;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+import ch.systemsx.cisd.common.image.IntensityRescaling;
+import ch.systemsx.cisd.common.image.IntensityRescaling.Levels;
+
+/**
+ * Transformation performed by
+ * {@link IntensityRescaling#rescaleIntensityLevelTo8Bits(BufferedImage, Levels)}.
+ * <p>
+ * Warning: The serialized version of this class can be stored in the database for each image.
+ * Moving this class to a different package or changing it in a backward incompatible way would make
+ * all the saved transformations invalid.
+ * 
+ * @author Tomasz Pylak
+ */
+@JsonObject("IntensityRangeImageTransformerFactory")
+public class IntensityRangeImageTransformerFactory implements IImageTransformerFactory
+{
+    private static final long serialVersionUID = 1L;
+
+    private final int blackPointIntensity;
+
+    private final int whitePointIntensity;
+
+    public IntensityRangeImageTransformerFactory(int blackPointIntensity, int whitePointIntensity)
+    {
+        this.blackPointIntensity = blackPointIntensity;
+        this.whitePointIntensity = whitePointIntensity;
+    }
+
+    public int getBlackPointIntensity()
+    {
+        return blackPointIntensity;
+    }
+
+    public int getWhitePointIntensity()
+    {
+        return whitePointIntensity;
+    }
+
+    @Override
+    public IImageTransformer createTransformer()
+    {
+        return new IImageTransformer()
+            {
+                @Override
+                public BufferedImage transform(BufferedImage image)
+                {
+                    if (IntensityRescaling.isNotGrayscale(image))
+                    {
+                        return image;
+                    }
+                    Levels levels = new Levels(blackPointIntensity, whitePointIntensity);
+                    return IntensityRescaling.rescaleIntensityLevelTo8Bits(image, levels);
+                }
+            };
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/utils/DropboxUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/utils/DropboxUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..2746b4ca1913026d2e7e8b1cb9591d36d6af670e
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/utils/DropboxUtils.java
@@ -0,0 +1,63 @@
+/*
+ * 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.dss.etl.dto.api.utils;
+
+import java.util.Collection;
+import java.util.Map;
+
+import ch.systemsx.cisd.common.geometry.SpatialPoint;
+import ch.systemsx.cisd.openbis.dss.etl.TileGeometryOracle;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Location;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.PlateUtils;
+
+/**
+ * @author Tomasz Pylak
+ */
+public class DropboxUtils
+{
+    /**
+     * Translates a row number into letter code. Thus, 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB,
+     * etc.
+     */
+    public static String translateRowNumberIntoLetterCode(int rowNumber)
+    {
+        return PlateUtils.translateRowNumberIntoLetterCode(rowNumber);
+    }
+
+    /**
+     * Figures the tile geometry based on all locations present in the it.
+     */
+    public static Geometry figureGeometry(Collection<Location> tileLocations)
+    {
+        return TileGeometryOracle.figureGeometry(tileLocations);
+    }
+
+    /**
+     * Tries to figure out tile locations based on their spatial coordinates.
+     * <p>
+     * Two spatial points (x1, y1) and (x2, y2) are assumed lie in the same tile when abs(x1-x2) <
+     * epsilon and abs(y1-y2) < epsilon.
+     * 
+     * @param epsilon see the javadoc of the method
+     */
+    public static Map<Integer/* tile number */, Location> tryFigureLocations(
+            Map<Integer/* tile number */, SpatialPoint> tileToSpatialPointMap, double epsilon)
+    {
+        return TileGeometryOracle.tryFigureLocations(tileToSpatialPointMap, epsilon);
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/BasicDataSetInformation.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/BasicDataSetInformation.java
index 99bcf07c6308dcf4cd84a876fa3c836c976150d9..a25f0eae3e3282f0844b136360b9debfb17749ea 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/BasicDataSetInformation.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/BasicDataSetInformation.java
@@ -16,74 +16,15 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.util.Arrays;
-
-import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
-import ch.systemsx.cisd.openbis.generic.shared.IServer;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
-
 /**
- * Basic attributes of a dataset connected to a sample and optionally to one parent dataset.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.BasicDataSetInformation} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public class BasicDataSetInformation extends DataSetInformation
+public class BasicDataSetInformation extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.BasicDataSetInformation
 {
-    private static final long serialVersionUID = IServer.VERSION;
-
-    private String fileFormatTypeCode;
-
-    // marks if a dataset is measured or derived from measured data
-    private boolean isMeasured = true;
-
-    /** Sets code of the dataset type */
-    public void setDatasetTypeCode(String datasetTypeCode)
-    {
-        DataSetType dataSetType = new DataSetType();
-        dataSetType.setCode(datasetTypeCode);
-        super.setDataSetType(dataSetType);
-    }
-
-    /** Mandatory: sets file format code. */
-    public void setFileFormatCode(String fileFormatCode)
-    {
-        this.fileFormatTypeCode = fileFormatCode;
-    }
-
-    /**
-     * Sets attributes of the connected sample - optional.
-     * <p>
-     * Alternatively, call
-     * {@link ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetUpdatable#setSample(ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.ISampleImmutable)}
-     * on the object returned by
-     * {@link ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetRegistrationTransaction#createNewDataSet()}.
-     */
-    public void setSample(String sampleSpaceCode, String sampleCode)
-    {
-        super.setSpaceCode(sampleSpaceCode);
-        super.setSampleCode(sampleCode);
-    }
-
-    /** attributes of the parent dataset - optional */
-    public void setParentDatasetCode(String parentDatasetCode)
-    {
-        super.setParentDataSetCodes(Arrays.asList(parentDatasetCode));
-    }
-
-    /** marks if a dataset is measured or derived from measured data */
-    public void setMeasured(boolean isMeasured)
-    {
-        this.isMeasured = isMeasured;
-    }
-
-    public String getFileFormatTypeCode()
-    {
-        return fileFormatTypeCode;
-    }
-
-    public boolean isMeasured()
-    {
-        return isMeasured;
-    }
 
+    private static final long serialVersionUID = 1L;
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/Channel.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/Channel.java
index 43fab945b936660c6c30087bc832221792675ef5..2e5551425c10e71e97e8be90ebe7450e54b57cca 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/Channel.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/Channel.java
@@ -1,168 +1,35 @@
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.awt.Color;
-import java.io.Serializable;
-
-import ch.systemsx.cisd.common.image.WavelengthColor;
-import ch.systemsx.cisd.common.reflection.AbstractHashable;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
 
 /**
- * A channel in which the image has been acquired.
- * <p>
- * Each channel has its <code>code</code> which uniquely identifies it in one experiment or dataset.
- * </p>
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public final class Channel extends AbstractHashable implements Serializable
+public final class Channel extends ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel
 {
     private static final long serialVersionUID = 1L;
 
-    private final String code;
-
-    private final String label;
-
-    private String description;
-
-    private Integer wavelength;
-
-    private ChannelColorRGB channelColorOrNull;
-
-    private ImageTransformation[] availableTransformations = new ImageTransformation[0];
-
-    /**
-     * Constructs a channel with a specified code and label. The channel will be presented in a
-     * default color.
-     */
-    public Channel(String code, String label)
+    public Channel(String code, String label,
+            ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor channelColorOrNull)
     {
-        this(code, label, (ChannelColorRGB) null);
+        super(code, label, channelColorOrNull);
     }
 
-    /**
-     * Constructs a channel with a specified code and label. The channel will be presented in a
-     * specified color.
-     */
     public Channel(String code, String label, ChannelColor channelColorOrNull)
     {
-        this(code, label, convertColor(channelColorOrNull));
+        super(code, label, channelColorOrNull);
     }
 
-    /**
-     * Constructs a channel with a specified code and label. The channel will be presented in a
-     * specified color.
-     */
     public Channel(String code, String label, ChannelColorRGB channelColorOrNull)
     {
-        assert code != null : "code is null";
-        assert label != null : "label is null";
-        this.label = label;
-        this.code = code;
-        this.channelColorOrNull = channelColorOrNull;
-    }
-
-    private static ChannelColorRGB convertColor(ChannelColor plainChannelColorOrNull)
-    {
-        if (plainChannelColorOrNull == null)
-        {
-            return null;
-        }
-        return plainChannelColorOrNull.getRGB();
-    }
-
-    public String getCode()
-    {
-        return code;
-    }
-
-    public String tryGetDescription()
-    {
-        return description;
-    }
-
-    public Integer tryGetWavelength()
-    {
-        return wavelength;
-    }
-
-    public String getLabel()
-    {
-        return label;
-    }
-
-    /**
-     * @return color for the specified channel which will be used to display merged channels images.
-     *         null only during dataset registration when default color should be used, afterwards
-     *         never null.
-     */
-    public ChannelColorRGB tryGetChannelColor()
-    {
-        return channelColorOrNull;
-    }
-
-    // never null, can be empty
-    public ImageTransformation[] getAvailableTransformations()
-    {
-        return availableTransformations;
+        super(code, label, channelColorOrNull);
     }
 
-    // ------------------- setters -------------------
-
-    /** Sets the description of the channel. Optional. */
-    public void setDescription(String description)
-    {
-        this.description = description;
-    }
-
-    /** Sets the wavelength of the light (in nanometers) used to acquire this channel. Optional. */
-    public void setWavelength(Integer wavelength)
-    {
-        this.wavelength = wavelength;
-    }
-
-    /**
-     * Sets the wavelength of the light (in nanometers) used to acquire this channel.<br>
-     * Additionally sets the channel color. The color is calculated for display on a computer
-     * monitor on the basis of the given wavelength using Bruton's algorithm. See <a
-     * href="http://www.midnightkite.com/color.html">COLOR SCIENCE web page</a> for details.
-     * <p>
-     * Optional.
-     */
-    public void setWavelengthAndColor(Integer wavelength)
-    {
-        this.wavelength = wavelength;
-        Color color = WavelengthColor.getColorForWavelength(wavelength);
-        setChannelColorRGB(convertColor(color));
-    }
-
-    private ChannelColorRGB convertColor(Color color)
-    {
-        return new ChannelColorRGB(color.getRed(), color.getGreen(), color.getBlue());
-    }
-
-    /** Sets the plain color in which this channel will be displayed. */
-    public void setChannelColor(ChannelColor channelColor)
-    {
-        this.channelColorOrNull = convertColor(channelColor);
-    }
-
-    /** Sets RGB color in which this channel will be displayed. */
-    public void setChannelColorRGB(ChannelColorRGB channelColor)
-    {
-        this.channelColorOrNull = channelColor;
-    }
-
-    /** Sets available transformations which can be applied to images of this channel on request. */
-    public void setAvailableTransformations(ImageTransformation[] transformations)
+    public Channel(String code, String label)
     {
-        if (transformations == null)
-        {
-            this.availableTransformations = new ImageTransformation[0];
-        } else
-        {
-            this.availableTransformations = transformations;
-        }
+        super(code, label);
     }
-
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColor.java
index 275b0fcfd15fd91c1fafa17fa936afa7a257fa8d..e1fbb8b140ff9e6c6a687560921c5a2aabc2e994 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColor.java
@@ -1,9 +1,10 @@
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
 /**
- * Allowed colors in which channels can be presented.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
 public enum ChannelColor
 {
@@ -68,4 +69,25 @@ public enum ChannelColor
                 throw new IllegalStateException("unhandled enum " + this);
         }
     }
+
+    public ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor getIndependentChannelColor()
+    {
+        switch (this)
+        {
+            case RED:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor.RED;
+            case GREEN:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor.GREEN;
+            case BLUE:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor.BLUE;
+            case RED_GREEN:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor.RED_GREEN;
+            case GREEN_BLUE:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor.GREEN_BLUE;
+            case RED_BLUE:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor.RED_BLUE;
+            default:
+                throw new IllegalStateException("unhandled enum " + this);
+        }
+    }
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorComponent.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorComponent.java
index 3d536df7dbaf6271038ed430b1fdcf49159c0935..48ed465546a3c64371d507426a1c2fc4360b2aa6 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorComponent.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorComponent.java
@@ -16,18 +16,61 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
+import java.util.LinkedList;
+import java.util.List;
+
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
 
 /**
- * Color component of an image which constitutes one channel. Useful if the image consists of all
- * channels merged together.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
 public enum ChannelColorComponent
 {
     RED, GREEN, BLUE;
 
+    public ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent getIndependentChannelColorComponent()
+    {
+        switch (this)
+        {
+            case BLUE:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent.BLUE;
+            case GREEN:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent.GREEN;
+            case RED:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent.RED;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the list of enums which are either of this type or of the version independent
+     * CahnnelColorComponent. Returns the list of the independent type
+     */
+    public static List<ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent> convertToIndependentChannelColorList(
+            List<?> inputList)
+    {
+        List<ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent> results =
+                new LinkedList<ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent>();
+        for (Object o : inputList)
+        {
+            if (o instanceof ChannelColorComponent)
+            {
+                results.add(((ChannelColorComponent) o).getIndependentChannelColorComponent());
+            } else if (o instanceof ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent)
+            {
+                results.add((ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent) o);
+            } else
+            {
+                throw new IllegalArgumentException(
+                        "List items must be of one of ChannelColorComponent types.");
+            }
+        }
+        return results;
+    }
+
     public static ColorComponent getColorComponent(ChannelColorComponent channelColorComponent)
     {
         switch (channelColorComponent)
@@ -39,7 +82,6 @@ public enum ChannelColorComponent
             case RED:
                 return ColorComponent.RED;
         }
-
         return null;
     }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorRGB.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorRGB.java
index 55d3e8bb53a33ceb57c4dd1eb3af8b4de12905a6..cdb75551fb0804854f97c57a8d1760df53d120f7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorRGB.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorRGB.java
@@ -16,86 +16,20 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.io.Serializable;
-
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ServiceVersionHolder;
-
 /**
- * RGB color components specify the color in which channel should be displayed.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public class ChannelColorRGB implements Serializable
+public class ChannelColorRGB extends ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB
 {
-    private static final long serialVersionUID = ServiceVersionHolder.VERSION;
-
-    private int r, g, b;
 
-    @SuppressWarnings("unused")
-    private ChannelColorRGB()
-    {
-    }
+    private static final long serialVersionUID = 1L;
 
     public ChannelColorRGB(int r, int g, int b)
     {
-        assert r >= 0 && r <= 255 : "invalid color " + r;
-        assert g >= 0 && g <= 255 : "invalid color " + g;
-        assert b >= 0 && b <= 255 : "invalid color " + b;
-
-        this.r = r;
-        this.g = g;
-        this.b = b;
-    }
-
-    public int getR()
-    {
-        return r;
-    }
-
-    public int getG()
-    {
-        return g;
-    }
-
-    public int getB()
-    {
-        return b;
-    }
-
-    @Override
-    public String toString()
-    {
-        return "Color(r=" + r + ", g=" + g + ", b=" + b + ")";
-    }
-
-    @Override
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + b;
-        result = prime * result + g;
-        result = prime * result + r;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        ChannelColorRGB other = (ChannelColorRGB) obj;
-        if (b != other.b)
-            return false;
-        if (g != other.g)
-            return false;
-        if (r != other.r)
-            return false;
-        return true;
+        super(r, g, b);
     }
 
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/FeatureListDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/FeatureListDataConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..50cf00b1b5341f8e5c923c4e33154259dd1e76e2
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/FeatureListDataConfig.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012 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.etl.dto.api.v1;
+
+import java.util.Collection;
+
+import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetUpdatable;
+
+/**
+ * The builder class for creation of feature lists.
+ * 
+ * @author Jakub Straszewski
+ */
+public class FeatureListDataConfig
+{
+    /**
+     * The name of this feature grouping.
+     */
+    private String name;
+
+    /**
+     * The list of features for this grouping
+     */
+    private Collection<String> featureList;
+
+    /**
+     * The feature vector container data set to which this list should be assigned
+     */
+    private IDataSetUpdatable containerDataSet;
+
+    public FeatureListDataConfig()
+    {
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    public Collection<String> getFeatureList()
+    {
+        return featureList;
+    }
+
+    public void setFeatureList(Collection<String> featureList)
+    {
+        this.featureList = featureList;
+    }
+
+    public IDataSetUpdatable getContainerDataSet()
+    {
+        return containerDataSet;
+    }
+
+    public void setContainerDataSet(IDataSetUpdatable containerDataSet)
+    {
+        this.containerDataSet = containerDataSet;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureVectorDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureVectorDataSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..22b85622f5d8f4fec1277fb657457a99ab0b48d4
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureVectorDataSet.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012 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.etl.dto.api.v1;
+
+import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet;
+
+/**
+ * Extension of {@link IDataSet} specific for feature vector data sets.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public interface IFeatureVectorDataSet extends IDataSet
+{
+    /**
+     * Sets the analysis procedure used to create the feature vectors.
+     */
+    public void setAnalysisProcedure(String analysisProcedure);
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IImagingDataSetRegistrationTransaction.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IImagingDataSetRegistrationTransaction.java
index 244d911060bb4cffdf45bb393ed7087778de2c33..ba5c1d7997aceeb50bb108da87095784efbe28fb 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IImagingDataSetRegistrationTransaction.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IImagingDataSetRegistrationTransaction.java
@@ -21,6 +21,7 @@ import java.io.File;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetRegistrationTransaction;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 
 /**
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IImagingDatasetFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IImagingDatasetFactory.java
index 26ca7ebfbdc72e788f9e4be403f90a3fdde0245f..126b9502fc4a35195e7ea3ec7cb6f42bc6a7fe09 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IImagingDatasetFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IImagingDatasetFactory.java
@@ -23,6 +23,8 @@ import java.util.Properties;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.v1.DataSetRegistrationService;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeaturesBuilder;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageFileInfo.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageFileInfo.java
index ab3150afc013e8e013f4ea195afcf7b2422789bd..db8cc9b0fd40c8b09c2c20b82c9e2f8c387bda87 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageFileInfo.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageFileInfo.java
@@ -1,183 +1,18 @@
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.io.Serializable;
-
-import ch.systemsx.cisd.hcs.Location;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
-
 /**
- * DTO with information about one image file
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public final class ImageFileInfo implements Serializable
+public final class ImageFileInfo extends ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo
 {
-    private static final long serialVersionUID = 1L;
-
-    private WellLocation wellLocationOrNull;
-
-    private Location tileLocation;
-
-    private String channelCode;
-
-    private final String imageRelativePath;
-
-    private Float timepointOrNull;
-
-    private Float depthOrNull;
-
-    private Integer seriesNumberOrNull;
-
-    private ImageIdentifier imageIdentifier;
 
-    private String uniqueImageIdentifier;
-
-    private String containerDataSetCode;
+    private static final long serialVersionUID = 1L;
 
     public ImageFileInfo(String channelCode, int tileRow, int tileColumn, String imageRelativePath)
     {
-        assert channelCode != null;
-        assert imageRelativePath != null;
-
-        this.channelCode = channelCode;
-        this.imageRelativePath = imageRelativePath;
-        setTile(tileRow, tileColumn);
-    }
-
-    public String tryGetUniqueStringIdentifier()
-    {
-        if (imageIdentifier != null)
-        {
-            return imageIdentifier.getUniqueStringIdentifier();
-        } else if (uniqueImageIdentifier != null)
-        {
-            return uniqueImageIdentifier;
-        }
-
-        return null;
-    }
-
-    public Integer tryGetWellRow()
-    {
-        return wellLocationOrNull == null ? null : wellLocationOrNull.getRow();
-    }
-
-    public Integer tryGetWellColumn()
-    {
-        return wellLocationOrNull == null ? null : wellLocationOrNull.getColumn();
-    }
-
-    public WellLocation tryGetWellLocation()
-    {
-        return wellLocationOrNull;
-    }
-
-    public boolean hasWellLocation()
-    {
-        return wellLocationOrNull != null;
-    }
-
-    public int getTileRow()
-    {
-        return tileLocation.getY();
-    }
-
-    public int getTileColumn()
-    {
-        return tileLocation.getX();
-    }
-
-    public String getChannelCode()
-    {
-        return channelCode;
-    }
-
-    public String getImageRelativePath()
-    {
-        return imageRelativePath;
-    }
-
-    public Float tryGetTimepoint()
-    {
-        return timepointOrNull;
-    }
-
-    public Float tryGetDepth()
-    {
-        return depthOrNull;
-    }
-
-    public Integer tryGetSeriesNumber()
-    {
-        return seriesNumberOrNull;
-    }
-
-    // --- setters
-
-    public void setImageIdentifier(ImageIdentifier imageIdentifier)
-    {
-        this.imageIdentifier = imageIdentifier;
-    }
-
-    public void setWell(int row, int column)
-    {
-        this.wellLocationOrNull = new WellLocation(row, column);
-    }
-
-    /** @return true if well row and column could be parsed */
-    public boolean setWell(String wellText)
-    {
-        try
-        {
-            this.wellLocationOrNull = WellLocation.parseLocationStr(wellText);
-        } catch (Exception e)
-        {
-            // do nothing
-        }
-        return wellLocationOrNull != null;
-    }
-
-    public void setTile(int row, int column)
-    {
-        this.tileLocation = Location.createLocationFromRowAndColumn(row, column);
-    }
-
-    public void setTimepoint(Float value)
-    {
-        this.timepointOrNull = value;
-    }
-
-    public void setDepth(Float value)
-    {
-        this.depthOrNull = value;
-    }
-
-    public void setSeriesNumber(Integer value)
-    {
-        this.seriesNumberOrNull = value;
-    }
-
-    public void setUniqueImageIdentifier(String uniqueImageIdentifier)
-    {
-        this.uniqueImageIdentifier = uniqueImageIdentifier;
-    }
-
-    public String getContainerDataSetCode()
-    {
-        return containerDataSetCode;
-    }
-
-    public void setContainerDataSetCode(String containerDataSetCode)
-    {
-        this.containerDataSetCode = containerDataSetCode;
-    }
-
-    @Override
-    public String toString()
-    {
-        return "ImageFileInfo [well=" + wellLocationOrNull + ", tile=" + tileLocation
-                + ", channel=" + channelCode + ", path=" + imageRelativePath + ", timepoint="
-                + timepointOrNull + ", depth=" + depthOrNull + ", seriesNumber="
-                + seriesNumberOrNull + "]";
+        super(channelCode, tileRow, tileColumn, imageRelativePath);
     }
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageIdentifier.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageIdentifier.java
index ce63badb1431b49939cc5d02fec6c3c2fc68228c..b11302b2353e9809a98347cd9c9abc9e337679ca 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageIdentifier.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageIdentifier.java
@@ -16,120 +16,20 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.io.Serializable;
-
-import ch.systemsx.cisd.imagereaders.ImageID;
-
 /**
- * Immutable value class of an image ID based on series index, time series index, focal plane index,
- * and color channel index. It will be used to identify images in a container image file format like
- * multi-page TIFF.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageIdentifier} instead
  * 
- * @author Franz-Josef Elmer
+ * @author Jakub Straszewski
  */
-public class ImageIdentifier implements Comparable<ImageIdentifier>, Serializable
+public class ImageIdentifier extends ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageIdentifier
 {
-    private static final long serialVersionUID = 1L;
-
-    public static final ImageIdentifier NULL = new ImageIdentifier(0, 0, 0, 0);
-
-    private final int seriesIndex;
 
-    private final int timeSeriesIndex;
-
-    private final int focalPlaneIndex;
-
-    private final int colorChannelIndex;
+    private static final long serialVersionUID = 1L;
 
-    /**
-     * Creates an instance for the specified series index, time series (or T) index, focal plane (or
-     * Z) index, color channel index.
-     */
     public ImageIdentifier(int seriesIndex, int timeSeriesIndex, int focalPlaneIndex,
             int colorChannelIndex)
     {
-        this.seriesIndex = seriesIndex;
-        this.timeSeriesIndex = timeSeriesIndex;
-        this.focalPlaneIndex = focalPlaneIndex;
-        this.colorChannelIndex = colorChannelIndex;
-    }
-
-    public int getSeriesIndex()
-    {
-        return seriesIndex;
-    }
-
-    public int getTimeSeriesIndex()
-    {
-        return timeSeriesIndex;
-    }
-
-    public int getFocalPlaneIndex()
-    {
-        return focalPlaneIndex;
-    }
-
-    public int getColorChannelIndex()
-    {
-        return colorChannelIndex;
-    }
-
-    public String getUniqueStringIdentifier()
-    {
-        return new ImageID(getSeriesIndex(), getTimeSeriesIndex(), getFocalPlaneIndex(),
-                getColorChannelIndex()).getID();
-    }
-
-    @Override
-    public int compareTo(ImageIdentifier that)
-    {
-        int diff = seriesIndex - that.seriesIndex;
-        if (diff != 0)
-        {
-            return diff;
-        }
-        diff = timeSeriesIndex - that.timeSeriesIndex;
-        if (diff != 0)
-        {
-            return diff;
-        }
-        diff = focalPlaneIndex - that.focalPlaneIndex;
-        if (diff != 0)
-        {
-            return diff;
-        }
-        return colorChannelIndex - that.colorChannelIndex;
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (obj == this)
-        {
-            return true;
-        }
-        if (obj instanceof ImageIdentifier == false)
-        {
-            return false;
-        }
-        ImageIdentifier that = (ImageIdentifier) obj;
-        return seriesIndex == that.seriesIndex && timeSeriesIndex == that.timeSeriesIndex
-                && focalPlaneIndex == that.focalPlaneIndex
-                && colorChannelIndex == that.colorChannelIndex;
-    }
-
-    @Override
-    public int hashCode()
-    {
-        return ((((seriesIndex * 37) + timeSeriesIndex) * 37) + focalPlaneIndex) * 37
-                + colorChannelIndex;
+        super(seriesIndex, timeSeriesIndex, focalPlaneIndex, colorChannelIndex);
     }
-
-    @Override
-    public String toString()
-    {
-        return seriesIndex + "." + timeSeriesIndex + "." + focalPlaneIndex + "."
-                + colorChannelIndex;
-    }
-
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageMetadata.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageMetadata.java
index f85739f2229b98fb6ccb0d004c86e3a71156c583..54089767f9f973dd9301d15271667196a99b8b92 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageMetadata.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageMetadata.java
@@ -1,159 +1,11 @@
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import org.apache.commons.lang.StringUtils;
-
 /**
- * Store well, channel and tile number to which an image belongs. Optionally stores
- * timepoint/depth-scan/image series number.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageMetadata} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public class ImageMetadata
+public class ImageMetadata extends ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageMetadata
 {
-    private String channelCode;
-
-    private int tileNumber;
-
-    private String well;
-
-    private Float timepointOrNull;
-
-    private Float depthOrNull;
-
-    private Integer seriesNumberOrNull;
-
-    private ImageIdentifier imageIdentifierOrNull;
-
-    public String getChannelCode()
-    {
-        return channelCode;
-    }
-
-    /** Sets channel code. */
-    public void setChannelCode(String channelCode)
-    {
-        this.channelCode = channelCode;
-    }
-
-    public int getTileNumber()
-    {
-        return tileNumber;
-    }
-
-    /** Sets tile number. It should start from 1. */
-    public void setTileNumber(int tileNumber)
-    {
-        this.tileNumber = tileNumber;
-    }
-
-    public String getWell()
-    {
-        return well;
-    }
-
-    /** Sets well code (example: "A1") */
-    public void setWell(String well)
-    {
-        this.well = well;
-    }
-
-    /** Sets the timepoint of the image. Optional. */
-    public void setTimepoint(Float value)
-    {
-        this.timepointOrNull = value;
-    }
-
-    /** Sets the depth at which the image has been scanned. Optional. */
-    public void setDepth(Float value)
-    {
-        this.depthOrNull = value;
-    }
-
-    /**
-     * Sets the integer series number of the image. Optional. Used to order images when there are no
-     * time or depth dimentions but there is a series of images for one well, channel and tile. Can
-     * be also used together with time and depth dimention.
-     */
-    public void setSeriesNumber(Integer value)
-    {
-        this.seriesNumberOrNull = value;
-    }
-
-    /**
-     * Sets the id of the image inside a container image file format. This is optional and not
-     * needed for image files which contain only one image.
-     */
-    public void setImageIdentifier(ImageIdentifier imageIdentifier)
-    {
-        imageIdentifierOrNull = imageIdentifier;
-    }
-
-    public Float tryGetTimepoint()
-    {
-        return timepointOrNull;
-    }
-
-    public Float tryGetDepth()
-    {
-        return depthOrNull;
-    }
-
-    public Integer tryGetSeriesNumber()
-    {
-        return seriesNumberOrNull;
-    }
-
-    public ImageIdentifier tryGetImageIdentifier()
-    {
-        return imageIdentifierOrNull;
-    }
-
-    /**
-     * Validates that tile number, channel and well (if argument is <code>false</code>) have been
-     * specified.
-     * 
-     * @throws IllegalStateException if the object is not valid.
-     */
-    public void ensureValid(boolean isMicroscopy)
-    {
-        if (tileNumber <= 0)
-        {
-            throw new IllegalStateException("Tile number has to be > 0, but is " + tileNumber);
-        }
-        if (StringUtils.isBlank(channelCode))
-        {
-            throw new IllegalStateException("Channel code is not specified");
-        }
-        if (StringUtils.isBlank(well) && isMicroscopy == false)
-        {
-            throw new IllegalStateException("Well is not specified");
-        }
-    }
-
-    @Override
-    public String toString()
-    {
-        StringBuffer sb = new StringBuffer();
-        sb.append("ImageMetadata [channelCode=" + channelCode + ", tileNumber=" + tileNumber
-                + ", well=" + well);
-        if (timepointOrNull != null)
-        {
-            sb.append(", timepointOrNull =" + timepointOrNull);
-        }
-        if (depthOrNull != null)
-        {
-            sb.append(", depthOrNull=" + depthOrNull);
-        }
-        if (seriesNumberOrNull != null)
-        {
-            sb.append(", seriesNumberOrNull=" + seriesNumberOrNull);
-        }
-        if (imageIdentifierOrNull != null)
-        {
-            sb.append(", imageIdentifierOrNull=" + imageIdentifierOrNull);
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java
index 5caa8a84cd36e88f6c54573ecb04b9df79a0d944..ffc0ddf3cae1bb2da4bc3d0214d63520ef76dec7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java
@@ -16,183 +16,15 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import ch.systemsx.cisd.base.image.IImageTransformerFactory;
-import ch.systemsx.cisd.common.reflection.AbstractHashable;
-import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
-
 /**
- * Configuration of how images should be stored. By default:
- * <UL>
- * <LI>no thumbnails are generated</LI>
- * <LI>original data are stored as they come (without additional compression).</LI>
- * </UL>
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageStorageConfiguraton} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public class ImageStorageConfiguraton extends AbstractHashable implements Serializable
+public class ImageStorageConfiguraton extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageStorageConfiguraton
 {
-    private static final long serialVersionUID = 1L;
-
-    /** Returns the default configuration. */
-    public static ImageStorageConfiguraton createDefault()
-    {
-        return new ImageStorageConfiguraton();
-    }
-
-    // --- State ----------
-
-    /** No thumbnails are generated by default. */
-    private List<ThumbnailsStorageFormat> thumbnailsStorageFormatsList =
-            new ArrayList<ThumbnailsStorageFormat>();
-
-    private OriginalDataStorageFormat originalDataStorageFormat =
-            OriginalDataStorageFormat.UNCHANGED;
-
-    /** No preferences by default, each storage processor decides by its own if it is not set. */
-    private Boolean storeChannelsOnExperimentLevelOrNull = null;
-
-    /**
-     * an image transformation to be applied before the image is stored.
-     */
-    private IImageTransformerFactory imageTransformerFactoryOrNull;
-
-    /**
-     * null by default, in this case some heuristics are used to find the right library to read the
-     * images, but it is slower and not all libraries are tried.
-     */
-    private ImageLibraryInfo imageLibraryOrNull = null;
-
-    // --- Getters & Setters ----------
-
-    /** @return null if no thumbnails should be generated */
-    public List<ThumbnailsStorageFormat> getThumbnailsStorageFormat()
-    {
-        return thumbnailsStorageFormatsList;
-    }
-
-    /** Set to null if no thumbnails should be generated. Overrides previous thumbnails settings. */
-    public void setThumbnailsStorageFormat(ThumbnailsStorageFormat thumbnailsStorageFormatOrNull)
-    {
-        thumbnailsStorageFormatsList.clear();
-        addThumbnailsStorageFormat(thumbnailsStorageFormatOrNull);
 
-    }
-
-    /**
-     * Adds new thumbnails setting to the list
-     */
-    public void addThumbnailsStorageFormat(ThumbnailsStorageFormat thumbnailsStorageFormatOrNull)
-    {
-        if (thumbnailsStorageFormatOrNull != null)
-        {
-            thumbnailsStorageFormatsList.add(thumbnailsStorageFormatOrNull);
-        }
-    }
-
-    /**
-     * Convenience method to switch on thumbnails generation with default settings. Overrides the
-     * results of {@link #setThumbnailsStorageFormat(ThumbnailsStorageFormat)}!.
-     */
-    public void switchOnThumbnailsGeneration()
-    {
-        thumbnailsStorageFormatsList.clear();
-        thumbnailsStorageFormatsList.add(new ThumbnailsStorageFormat());
-    }
-
-    public OriginalDataStorageFormat getOriginalDataStorageFormat()
-    {
-        return originalDataStorageFormat;
-    }
-
-    public void setOriginalDataStorageFormat(OriginalDataStorageFormat originalDataStorageFormat)
-    {
-        this.originalDataStorageFormat = originalDataStorageFormat;
-    }
-
-    /**
-     * Signalizes that the channels should be saved on experiment level rather than dataset level.
-     * Will be ignored in case of microscopy where all channels are always saved at dataset level.
-     */
-    public void setStoreChannelsOnExperimentLevel(boolean storeChannelsOnExperimentLevel)
-    {
-        this.storeChannelsOnExperimentLevelOrNull = storeChannelsOnExperimentLevel;
-    }
-
-    public Boolean getStoreChannelsOnExperimentLevel()
-    {
-        return storeChannelsOnExperimentLevelOrNull;
-    }
-
-    public IImageTransformerFactory getImageTransformerFactory()
-    {
-        return imageTransformerFactoryOrNull;
-    }
-
-    /**
-     * Allows for applying an image transformation on the fly when an image is fetched.
-     */
-    public void setImageTransformerFactory(IImageTransformerFactory transformerFactory)
-    {
-        this.imageTransformerFactoryOrNull = transformerFactory;
-    }
-
-    /** Sets the library which should be used to read the images. */
-    public void setImageLibrary(ImageLibraryInfo imageLibrary)
-    {
-        this.imageLibraryOrNull = imageLibrary;
-    }
-
-    /**
-     * @return library which should be used to read the images or null if the library is not
-     *         specified.
-     */
-    public ImageLibraryInfo tryGetImageLibrary()
-    {
-        return imageLibraryOrNull;
-    }
-
-    @Override
-    public String toString()
-    {
-        final StringBuilder buffer = new StringBuilder(super.toString());
-        if (originalDataStorageFormat != OriginalDataStorageFormat.UNCHANGED)
-        {
-            appendNameAndObject(buffer, "original data storage format",
-                    originalDataStorageFormat.toString());
-        }
-        if (thumbnailsStorageFormatsList.size() > 0)
-        {
-            for (ThumbnailsStorageFormat thumbnailsStorageFormat : thumbnailsStorageFormatsList)
-            {
-                appendNameAndObject(buffer, "thumbnails", thumbnailsStorageFormat.toString());
-            }
-        }
-        if (storeChannelsOnExperimentLevelOrNull != null)
-        {
-            appendNameAndObject(buffer, "store channels on experiment level",
-                    storeChannelsOnExperimentLevelOrNull);
-        }
-        if (imageTransformerFactoryOrNull != null)
-        {
-            appendNameAndObject(buffer, "image transformation", "present");
-        }
-        if (imageLibraryOrNull != null)
-        {
-            appendNameAndObject(buffer, "image library", imageLibraryOrNull.toString());
-        }
-        return buffer.toString();
-    }
-
-    protected static final void appendNameAndObject(final StringBuilder buffer, final String name,
-            final Object object)
-    {
-        if (object != null)
-        {
-            buffer.append(name).append("::").append(object).append(";");
-        }
-    }
-}
+    private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IntensityRange.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IntensityRange.java
index e74cb9f4fbdcc71e67af5b6e66500afb330307c0..213361f4a46ef5fe607744ec9f151e86698bfafd 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IntensityRange.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IntensityRange.java
@@ -17,42 +17,16 @@
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
 /**
- * The intensity range in a distribution of pixel values for a given symmetric quantile value.
- *
- * @author Bernd Rinn
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.IntensityRange} instead
+ * 
+ * @author Jakub Straszewski
  */
-public class IntensityRange
+public class IntensityRange extends ch.systemsx.cisd.openbis.dss.etl.dto.api.IntensityRange
 {
-    final int blackPoint;
-
-    final int whitePoint;
 
     public IntensityRange(int blackPoint, int whitePoint)
     {
-        this.blackPoint = blackPoint;
-        this.whitePoint = whitePoint;
-    }
-
-    /**
-     * The minimal level (black point).
-     */
-    public int getBlackPoint()
-    {
-        return blackPoint;
-    }
-
-    /**
-     * The maximal level (white point).
-     */
-    public int getWhitePoint()
-    {
-        return whitePoint;
-    }
-
-    @Override
-    public String toString()
-    {
-        return "MinMax [minLevel=" + blackPoint + ", maxLevel=" + whitePoint + "]";
+        super(blackPoint, whitePoint);
     }
-
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/Location.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/Location.java
index eb3049f0e712dd57dc542f62bb0e32a8dd3af597..4b764d6da1c3ecb648bcb4f50ccb8505c1a42cbc 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/Location.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/Location.java
@@ -1,63 +1,16 @@
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
 /**
- * Auxiliary structure to store tile location on the well. The top left tile has coordinates (1,1).
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.Location} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public class Location
+public class Location extends ch.systemsx.cisd.openbis.dss.etl.dto.api.Location
 {
-    private final int row, column;
 
-    /** Note: The top left tile has coordinates (1,1). */
     public Location(int row, int column)
     {
-        this.row = row;
-        this.column = column;
-    }
-
-    public int getRow()
-    {
-        return row;
-    }
-
-    public int getColumn()
-    {
-        return column;
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj)
-        {
-            return true;
-        }
-        if (obj == null)
-        {
-            return false;
-        }
-        if (getClass() != obj.getClass())
-        {
-            return false;
-        }
-        Location other = (Location) obj;
-        return column == other.column && row == other.row;
-    }
-
-    @Override
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + column;
-        result = prime * result + row;
-        return result;
-    }
-
-    @Override
-    public String toString()
-    {
-        return "[" + row + ":" + column + "]";
+        super(row, column);
     }
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/OriginalDataStorageFormat.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/OriginalDataStorageFormat.java
index 26182aec37773073d5b4bc6f27bcbff4e353932a..7324346157b57e0ca0ef05753906a99b4cfdac9f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/OriginalDataStorageFormat.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/OriginalDataStorageFormat.java
@@ -37,4 +37,18 @@ public enum OriginalDataStorageFormat
         return this == OriginalDataStorageFormat.HDF5
                 || this == OriginalDataStorageFormat.HDF5_COMPRESSED;
     }
+
+    public ch.systemsx.cisd.openbis.dss.etl.dto.api.OriginalDataStorageFormat getIndependentOriginalDataStorageFormat()
+    {
+        switch (this)
+        {
+            case HDF5:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.OriginalDataStorageFormat.HDF5;
+            case HDF5_COMPRESSED:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.OriginalDataStorageFormat.HDF5_COMPRESSED;
+            case UNCHANGED:
+                return ch.systemsx.cisd.openbis.dss.etl.dto.api.OriginalDataStorageFormat.UNCHANGED;
+        }
+        return null; // impossible
+    }
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleFeatureVectorDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleFeatureVectorDataConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..ddb2f14475de7265c277cdd8cd25c1b4dc49c876
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleFeatureVectorDataConfig.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2012 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.etl.dto.api.v1;
+
+import java.util.Properties;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeaturesBuilder;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeaturesBuilder;
+
+/**
+ * Configuration for creating a feature vector data set.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class SimpleFeatureVectorDataConfig
+{
+    private Properties properties;
+    private IFeaturesBuilder featuresBuilder;
+    
+    /**
+     * Creates an instance with undefined properties assuming that the {@link FeaturesBuilder} is
+     * used to create the feature vectors.
+     */
+    public SimpleFeatureVectorDataConfig()
+    {
+    }
+
+    /**
+     * Creates an instance for the specified properties object which is used to configure parsing of
+     * a feature vector file.
+     */
+    public SimpleFeatureVectorDataConfig(Properties properties)
+    {
+        this.properties = properties;
+    }
+    
+    public IFeaturesBuilder getFeaturesBuilder()
+    {
+        if (featuresBuilder == null)
+        {
+            featuresBuilder = new FeaturesBuilder();
+        }
+        return featuresBuilder;
+    }
+
+    public Properties getProperties()
+    {
+        return properties;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageContainerDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageContainerDataConfig.java
index a426593cbfe295ec5d809f7f2b6b939fa521e9ed..18d40e6fe8820a6a34ea169e67dd7b71010f9062 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageContainerDataConfig.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageContainerDataConfig.java
@@ -16,54 +16,13 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.util.List;
-
 /**
- * Subclass of {@link SimpleImageDataConfig} for container image files which creates
- * {@link ImageMetadata} based on {@link ImageIdentifier} using the following simple mapping:
- * <ul>
- * <li>ImageMetadata.seriesNumber = ImageIdentifier.seriesIndex + 1
- * <li>ImageMetadata.timePoint = ImageIdentifier.timeSeriesIndex
- * <li>ImageMetadata.depth = ImageIdentifier.focalPlaneIndex
- * <li>ImageMetadata.channelCode = 'CHANNEL-' + (ImageIdentifier.colorChannelIndex + 1)
- * <li>ImageMetadata.tileNumber = 1
- * </ul>
- * ImageMetadata.well will be filled with return value of method
- * {@link #tryToExtractWell(ImageIdentifier)}.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageContainerDataConfig} instead
  * 
- * @author Franz-Josef Elmer
+ * @author Jakub Straszewski
  */
-public class SimpleImageContainerDataConfig extends SimpleImageDataConfig
+public class SimpleImageContainerDataConfig extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageContainerDataConfig
 {
-
-    @Override
-    public ImageMetadata[] extractImagesMetadata(String imagePath,
-            List<ImageIdentifier> imageIdentifiers)
-    {
-        ImageMetadata[] metaData = new ImageMetadata[imageIdentifiers.size()];
-        for (int i = 0, n = imageIdentifiers.size(); i < n; i++)
-        {
-            ImageIdentifier imageIdentifier = imageIdentifiers.get(i);
-            ImageMetadata imageMetadata = new ImageMetadata();
-            imageMetadata.setImageIdentifier(imageIdentifier);
-            imageMetadata.setSeriesNumber(imageIdentifier.getSeriesIndex() + 1);
-            imageMetadata.setTimepoint(new Float(imageIdentifier.getTimeSeriesIndex()));
-            imageMetadata.setDepth(new Float(imageIdentifier.getFocalPlaneIndex()));
-            imageMetadata.setChannelCode("CHANNEL-" + (imageIdentifier.getColorChannelIndex() + 1));
-            imageMetadata.setWell(tryToExtractWell(imageIdentifier));
-            imageMetadata.setTileNumber(1);
-            metaData[i] = imageMetadata;
-        }
-        return metaData;
-    }
-
-    /**
-     * Tries to extract well from the specified image identifier. Default implementation returns
-     * <code>null</code>. In case of screening this method can be overridden.
-     */
-    public String tryToExtractWell(ImageIdentifier imageIdentifier)
-    {
-        return null;
-    }
-
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java
index 83783da72cf29aad9856b0c136a9ba1ed8a5c5e7..21131836b6a61fb24ce4ea26fb99edf734d60480 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java
@@ -16,966 +16,13 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import ch.systemsx.cisd.base.image.IImageTransformerFactory;
-import ch.systemsx.cisd.common.shared.basic.string.StringUtils;
-import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails.DefaultThumbnailsConfiguration;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails.IThumbnailsConfiguration;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails.ResolutionBasedThumbnailsConfiguration;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails.ZoomLevelBasedThumbnailsConfiguration;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ConvertToolImageTransformerFactory;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformation;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformationBuffer;
-import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
-import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
-
 /**
- * Allows to configure extraction of images for a plate or microscopy sample.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-abstract public class SimpleImageDataConfig
+abstract public class SimpleImageDataConfig extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig
 {
-    // --- one of the following two methods has to be overridden -----------------
-
-    /**
-     * Extracts tile number, channel code and well code for a given relative path to a single image.
-     * This method should overridden to deal with files containing single images. It is ignored if
-     * {@link #extractImagesMetadata(String, List)} is overridden as well.
-     * <p>
-     * It will be called for each file found in the incoming directory which has the extension
-     * returned by {@link #getRecognizedImageExtensions()}.
-     * </p>
-     * To deal with image containers (like multi-page TIFF files) override
-     * {@link #extractImagesMetadata(String, List)} instead, otherwise leave that method unchanged.
-     */
-    public ImageMetadata extractImageMetadata(String imagePath)
-    {
-        throw new UnsupportedOperationException(
-                "One of the extractImageMetadata() methods has to be implemented.");
-    }
-
-    /**
-     * Returns meta-data for each image in the specified image container. This method should
-     * overridden to deal with container images (like multi-page TIFF files).
-     * <p>
-     * This implementation returns the result of {@link #extractImageMetadata(String)} wrapped in an
-     * array, image identifiers are ignored.
-     * </p>
-     * 
-     * @param imagePath path to the single image or container of many images
-     * @param imageIdentifiers Identifiers of all images contained in the image file.
-     */
-    public ImageMetadata[] extractImagesMetadata(String imagePath,
-            List<ImageIdentifier> imageIdentifiers)
-    {
-
-        ImageMetadata imageMetadata = extractImageMetadata(imagePath);
-        return (imageMetadata != null) ? new ImageMetadata[]
-            { imageMetadata } : new ImageMetadata[0];
-    }
-
-    // --- methods which can be overridden -----------------
-
-    /**
-     * By default layouts all images in one row by returning (1, maxTileNumber) geometry.Can be
-     * overridden in subclasses.
-     * 
-     * @param imageMetadataList a list of metadata for each encountered image
-     * @param maxTileNumber the biggest tile number among all encountered images
-     * @return the width and height of the matrix of tiles (a.k.a. fields or sides) in the well.
-     */
-    public Geometry getTileGeometry(List<? extends ImageMetadata> imageMetadataList,
-            int maxTileNumber)
-    {
-        return Geometry.createFromRowColDimensions(1, maxTileNumber);
-    }
-
-    /**
-     * For a given tile number and tiles geometry returns (x,y) which describes where the tile is
-     * located on the well. Can be overridden in subclasses.<br>
-     * Note: The top left tile has coordinates (1,1).
-     * 
-     * @param tileNumber number of the tile extracted by {@link #extractImageMetadata}.
-     * @param tileGeometry the geometry of the well matrix returned by {@link #getTileGeometry}.
-     */
-    public Location getTileCoordinates(int tileNumber, Geometry tileGeometry)
-    {
-        int columns = tileGeometry.getWidth();
-        int row = ((tileNumber - 1) / columns) + 1;
-        int col = ((tileNumber - 1) % columns) + 1;
-        return new Location(row, col);
-    }
-
-    /**
-     * <p>
-     * Creates channel description for a given code. Can be overridden in subclasses.
-     * </p>
-     * By default the channel label will be equal to the code. Channel color returned by
-     * {@link #getChannelColor(String)} will be used.
-     */
-    public Channel createChannel(String channelCode)
-    {
-        ChannelColorRGB channelColorOrNull = tryGetChannelColor(channelCode.toUpperCase());
-        ImageTransformation[] availableTransformations =
-                getAvailableChannelTransformations(channelCode);
-        String label = channelCode;
-        String normalizedChannelCode = CodeNormalizer.normalize(channelCode);
-        Channel channel = new Channel(normalizedChannelCode, label, channelColorOrNull);
-        channel.setAvailableTransformations(availableTransformations);
-        return channel;
-    }
-
-    private ChannelColorRGB tryGetChannelColor(String channelCode)
-    {
-        ChannelColor channelColor = getChannelColor(channelCode);
-        ChannelColorRGB channelColorRGB = getChannelColorRGB(channelCode);
-        if (channelColorRGB != null && channelColor != null)
-        {
-            throw new IllegalStateException(String.format(
-                    "Color for channel '%s' is specified in two ways: %s and %s", channelColor,
-                    channelColorRGB));
-        }
-
-        if (channelColor != null)
-        {
-            return channelColor.getRGB();
-        } else
-        {
-            return channelColorRGB;
-        }
-    }
-
-    /**
-     * Sets available transformations which can be applied to images of the specified channel (on
-     * user's request).
-     * <p>
-     * Can be overridden in subclasses. The easiest way to create transformations is to use
-     * {@link ImageTransformationBuffer} class.
-     * <p>
-     * By default returns null.
-     */
-    public ImageTransformation[] getAvailableChannelTransformations(String channelCode)
-    {
-        return null;
-    }
-
-    /**
-     * Has the same effect as {@link #getChannelColorRGB(String)}, but can return only plain colors.
-     */
-    public ChannelColor getChannelColor(String channelCode)
-    {
-        return null;
-    }
-
-    /**
-     * Returns RGB color for the specified channel. It will be used to display merged channels
-     * images.
-     * <p>
-     * Can be overridden in subclasses. It is ignored if {@link #createChannel(String)} is
-     * overridden as well. One should not override {@link #getChannelColor(String)} and
-     * {@link #getChannelColorRGB(String)} at the same time.
-     * </p>
-     * By default returns null (the arbitrary color will be set).
-     */
-    public ChannelColorRGB getChannelColorRGB(String channelCode)
-    {
-        return null;
-    }
-
-    // --- auxiliary structures ----------------------------------------------
-
-    private String mainDatasetTypeCode;
-
-    private String fileFormatCode = ScreeningConstants.UNKNOWN_FILE_FORMAT;
-
-    private String plateCode;
-
-    private String spaceCode;
-
-    private boolean isMeasured = false;
-
-    private String[] recognizedImageExtensions = new String[]
-        { "tiff", "tif", "png", "gif", "jpg", "jpeg", "c01" };
-
-    private List<IThumbnailsConfiguration> imagePyramid = new ArrayList<IThumbnailsConfiguration>();
-
-    private int maxThumbnailWidthAndHeight = 256;
-
-    private boolean generateThumbnailsWithImageMagic = true;
-
-    private List<String> thumbnailsGenerationImageMagicParams = Collections.emptyList();
-
-    private boolean generateThumbnailsIn8BitHighQuality = false;
-
-    private double allowedMachineLoadDuringThumbnailsGeneration = 1.0;
-
-    private boolean storeChannelsOnExperimentLevel = false;
-
-    private OriginalDataStorageFormat originalDataStorageFormat =
-            OriginalDataStorageFormat.UNCHANGED;
-
-    private String convertTransformationCliArgumentsOrNull;
-
-    private ImageLibraryInfo imageLibraryInfoOrNull;
-
-    private boolean isMicroscopy;
-
-    // If null then no common intensity rescaling parameters are computed.
-    // If empty the computation will take place for all channels, otherwise only for specified
-    // channels.
-    private List<String> computeCommonIntensityRangeOfAllImagesForChannelsOrNull = null;
-
-    private float computeCommonIntensityRangeOfAllImagesThreshold =
-            ImageUtil.DEFAULT_IMAGE_OPTIMAL_RESCALING_FACTOR;
-
-    private String computeCommonIntensityRangeOfAllImagesLabel = "Optimal (series)";
-
-    private boolean computeCommonIntensityRangeOfAllImagesIsDefault = true;
-
-    private Map<String, IntensityRange> fixedIntensityRangeForAllImages;
-
-    private String thumbnailsFileFormat;
-
-    private List<Channel> channels;
-
-    private List<ChannelColorComponent> channelColorComponentsOrNull;
-
-    // --- getters & setters ----------------------------------------------
-
-    public ImageStorageConfiguraton getImageStorageConfiguration()
-    {
-        ImageStorageConfiguraton imageStorageConfiguraton =
-                ImageStorageConfiguraton.createDefault();
-        imageStorageConfiguraton
-                .setStoreChannelsOnExperimentLevel(isStoreChannelsOnExperimentLevel());
-        imageStorageConfiguraton.setOriginalDataStorageFormat(getOriginalDataStorageFormat());
-        for (IThumbnailsConfiguration thumbnailsConfiguration : imagePyramid)
-        {
-            imageStorageConfiguraton.addThumbnailsStorageFormat(thumbnailsConfiguration
-                    .getThumbnailsStorageFormat(this));
-        }
-        if (false == StringUtils.isBlank(convertTransformationCliArgumentsOrNull))
-        {
-            IImageTransformerFactory convertTransformerFactory =
-                    new ConvertToolImageTransformerFactory(convertTransformationCliArgumentsOrNull);
-            imageStorageConfiguraton.setImageTransformerFactory(convertTransformerFactory);
-
-        }
-        imageStorageConfiguraton.setImageLibrary(imageLibraryInfoOrNull);
-        return imageStorageConfiguraton;
-    }
-
-    public String getPlateSpace()
-    {
-        return spaceCode;
-    }
-
-    public String getPlateCode()
-    {
-        return plateCode;
-    }
-
-    public String[] getRecognizedImageExtensions()
-    {
-        return recognizedImageExtensions;
-    }
-
-    public boolean isGenerateThumbnails()
-    {
-        return imagePyramid.size() > 0;
-    }
-
-    public int getMaxThumbnailWidthAndHeight()
-    {
-        return maxThumbnailWidthAndHeight;
-    }
-
-    public double getAllowedMachineLoadDuringThumbnailsGeneration()
-    {
-        return allowedMachineLoadDuringThumbnailsGeneration;
-    }
-
-    public boolean isStoreChannelsOnExperimentLevel()
-    {
-        return storeChannelsOnExperimentLevel;
-    }
-
-    public OriginalDataStorageFormat getOriginalDataStorageFormat()
-    {
-        return originalDataStorageFormat;
-    }
-
-    public String tryGetConvertTransformationCliArguments()
-    {
-        return convertTransformationCliArgumentsOrNull;
-    }
-
-    public List<String> getComputeCommonIntensityRangeOfAllImagesForChannels()
-    {
-        return computeCommonIntensityRangeOfAllImagesForChannelsOrNull;
-    }
-
-    public float getComputeCommonIntensityRangeOfAllImagesThreshold()
-    {
-        return computeCommonIntensityRangeOfAllImagesThreshold;
-    }
-
-    public boolean isFixedIntensityRangeForAllImagesDefined()
-    {
-        return fixedIntensityRangeForAllImages != null;
-    }
-
-    public Map<String, IntensityRange> getFixedIntensityRangeForAllImages()
-    {
-        return fixedIntensityRangeForAllImages;
-    }
-
-    public String getComputeCommonIntensityRangeOfAllImagesLabel()
-    {
-        return computeCommonIntensityRangeOfAllImagesLabel;
-    }
-
-    public boolean isComputeCommonIntensityRangeOfAllImagesDefault()
-    {
-        return computeCommonIntensityRangeOfAllImagesIsDefault;
-    }
-
-    public List<Channel> getChannels()
-    {
-        return channels;
-    }
-
-    public List<ChannelColorComponent> getChannelColorComponentsOrNull()
-    {
-        return channelColorComponentsOrNull;
-    }
-
-    // ----- Setters -------------------------
-
-    /**
-     * Sets the existing plate to which the dataset should belong.
-     * 
-     * @param spaceCode space where the plate for which the dataset has been acquired exist
-     * @param plateCode code of the plate to which the dataset will belong
-     */
-    public void setPlate(String spaceCode, String plateCode)
-    {
-        this.spaceCode = spaceCode;
-        this.plateCode = plateCode;
-    }
-
-    /**
-     * Only files with these extensions will be recognized as images (e.g. ["jpg", "png"]).<br>
-     * By default it is set to [ "tiff", "tif", "png", "gif", "jpg", "jpeg", "c01" ].
-     */
-    public void setRecognizedImageExtensions(String[] recognizedImageExtensions)
-    {
-        this.recognizedImageExtensions = recognizedImageExtensions;
-    }
-
-    /** Sets all channels available in the data set. */
-    public void setChannels(List<Channel> channels)
-    {
-        this.channels = channels;
-    }
-
-    /**
-     * Use this method if channels are encoded in color components of one image (or in other words:
-     * each image contains merged channels). For each channel you have to specify the corresponding
-     * color component of the image.
-     */
-    public void setChannels(List<Channel> channels,
-            List<ChannelColorComponent> channelColorComponents)
-    {
-        this.channels = channels;
-        channelColorComponentsOrNull = channelColorComponents;
-    }
-
-    /** should thumbnails be generated? False by default. */
-    public void setGenerateThumbnails(boolean generateThumbnails)
-    {
-        imagePyramid.clear();
-        imagePyramid.add(new DefaultThumbnailsConfiguration());
-    }
-
-    /**
-     * See {@link #setGenerateImageRepresentations}.
-     * 
-     * @deprecated use {@link #setGenerateImageRepresentations} instead.
-     */
-    @Deprecated
-    public void setGenerateImagePyramid(IThumbnailsConfiguration[] elements)
-    {
-        setGenerateImageRepresentations(elements);
-    }
-
-    /**
-     * See {@link #setGenerateImageRepresentationsUsingScaleFactors}.
-     * 
-     * @deprecated use {@link #setGenerateImageRepresentationsUsingScaleFactors} instead.
-     */
-    @Deprecated
-    public void setGenerateImagePyramidWithScaleFactors(double[] zoomLevels)
-    {
-        setGenerateImageRepresentationsUsingScaleFactors(zoomLevels);
-    }
-
-    /**
-     * See {@link #setGenerateImageRepresentationsUsingImageResolutions}.
-     * 
-     * @deprecated use {@link #setGenerateImageRepresentationsUsingImageResolutions} instead.
-     */
-    @Deprecated
-    public void setGenerateImagePyramidWithImageResolution(String[] resolutions)
-    {
-        setGenerateImageRepresentationsUsingImageResolutions(resolutions);
-    }
-
-    /**
-     * Registers a request for alternate image representations to be generated based on the original
-     * image. The format of the alternate representations is specified by the
-     * {@link IThumbnailsConfiguration} formats argument.
-     * 
-     * @param formats The formats of the image generated representations. One image representation
-     *            will be created for each format.
-     */
-    public void setGenerateImageRepresentations(IThumbnailsConfiguration[] formats)
-    {
-        imagePyramid.clear();
-        imagePyramid.addAll(Arrays.asList(formats));
-    }
-
-    /**
-     * Registers a request for alternate image representations to be generated based on the original
-     * image. The alternate image representations vary with respect to resolution from the original
-     * image.
-     * 
-     * @param scaleFactors The scale factors applied to the original resolution. Scale factors must
-     *            be greater than 0.
-     */
-    public void setGenerateImageRepresentationsUsingScaleFactors(double[] scaleFactors)
-    {
-        imagePyramid.clear();
-        if (scaleFactors == null)
-        {
-            return;
-        }
-
-        // Verify the arguments
-        for (double scaleFactor : scaleFactors)
-        {
-            // This check is duplicated in addImageRepresentationUsingScale
-            if (scaleFactor <= 0)
-            {
-                throw new IllegalArgumentException(
-                        "Scale factors for generated image representations must be greater than 0. "
-                                + scaleFactor + " <= 0");
-            }
-        }
-        for (double scale : scaleFactors)
-        {
-            addGeneratedImageRepresentationWithScale(scale);
-        }
-    }
-
-    /**
-     * Registers a request for an alternate image representation to be generated based on the
-     * original image. The alternate image representations vary with respect to resolution from the
-     * original image.
-     * 
-     * @param scale The scale factor applied to the original resolution. Scale factors must be
-     *            greater than 0.
-     * @return The configuration for the image representation
-     */
-    public IThumbnailsConfiguration addGeneratedImageRepresentationWithScale(double scale)
-    {
-        if (scale <= 0)
-        {
-            throw new IllegalArgumentException(
-                    "Scale factors for generated image representations must be greater than 0. "
-                            + scale + " <= 0");
-        }
-        ZoomLevelBasedThumbnailsConfiguration imageRep =
-                new ZoomLevelBasedThumbnailsConfiguration(scale);
-        imagePyramid.add(imageRep);
-        return imageRep;
-    }
-
-    /**
-     * Registers a request for alternate image representations to be generated based on the original
-     * image. The alternate image representations vary with respect to resolution from the original
-     * image. By default, allow enlarging. Use
-     * {@link #setGenerateImageRepresentationsWithoutEnlargingUsingImageResolutions(String[])} to
-     * explicitly prevent enlarging.
-     * 
-     * @param resolutions The resolutions
-     */
-    public void setGenerateImageRepresentationsUsingImageResolutions(String[] resolutions)
-    {
-        setGenerateImageRepresentationsUsingImageResolutions(resolutions, true);
-    }
-
-    /**
-     * Registers a request for alternate image representations to be generated based on the original
-     * image. The alternate image representations vary with respect to resolution from the original
-     * image. This method throws an exception if the requested resolution results in the image being
-     * enlarged. Use {@link #setGenerateImageRepresentationsUsingImageResolutions(String[])} to
-     * allow enlarging.
-     * 
-     * @param resolutions The resolutions
-     */
-    public void setGenerateImageRepresentationsWithoutEnlargingUsingImageResolutions(
-            String[] resolutions)
-    {
-        setGenerateImageRepresentationsUsingImageResolutions(resolutions, false);
-    }
-
-    /**
-     * Registers a request for alternate image representations to be generated based on the original
-     * image. The alternate image representations vary with respect to resolution from the original
-     * image.
-     * 
-     * @param resolutions The resolutions
-     * @param allowEnlarging If true, resolutions larger than the original size of the image are
-     *            allowed
-     */
-    private void setGenerateImageRepresentationsUsingImageResolutions(String[] resolutions,
-            boolean allowEnlarging)
-    {
-        imagePyramid.clear();
-        if (resolutions != null)
-        {
-            for (String resolution : resolutions)
-            {
-                addGeneratedImageRepresentationWithResolution(resolution, allowEnlarging);
-            }
-        }
-    }
-
-    /**
-     * Registers a request for an alternate image representation to be generated based on the
-     * original image. The alternate image representations vary with respect to resolution from the
-     * original image. Enlarging is allowed. To prevent enlarging of the image, use
-     * {@link #addGeneratedImageRepresentationWithoutEnlargingWithResolution}.
-     * 
-     * @param resolution The resolution of the representation.
-     * @return The configuration for the image representation.
-     */
-    public IThumbnailsConfiguration addGeneratedImageRepresentationWithResolution(String resolution)
-    {
-        return addGeneratedImageRepresentationWithResolution(resolution, true);
-    }
-
-    /**
-     * Registers a request for an alternate image representation to be generated based on the
-     * original image. The alternate image representations vary with respect to resolution from the
-     * original image. Enlarging is not allowed. To allow enlarging of the image, use
-     * {@link #addGeneratedImageRepresentationWithResolution}.
-     * 
-     * @param resolution The resolution of the representation.
-     * @return The configuration for the image representation.
-     */
-    public IThumbnailsConfiguration addGeneratedImageRepresentationWithoutEnlargingWithResolution(
-            String resolution)
-    {
-        return addGeneratedImageRepresentationWithResolution(resolution, false);
-    }
-
-    /**
-     * Registers a request for an alternate image representation to be generated based on the
-     * original image. The alternate image representations vary with respect to resolution from the
-     * original image.
-     * 
-     * @param resolution The resolution of the representation.
-     * @param allowEnlarging If true, the generated representation may be <b>larger</b> than the
-     *            original image.
-     * @return The configuration for the image representation.
-     */
-    private IThumbnailsConfiguration addGeneratedImageRepresentationWithResolution(
-            String resolution, boolean allowEnlarging)
-    {
-        String[] dimension = resolution.split("x");
-        if (dimension.length != 2)
-        {
-            throw new IllegalArgumentException(
-                    "Resolution must be specified in format width x height, e. g. '400x300', but was: '"
-                            + resolution + "'");
-        }
-        int width = Integer.parseInt(dimension[0].trim());
-        int height = Integer.parseInt(dimension[1].trim());
-        ResolutionBasedThumbnailsConfiguration imageRep =
-                new ResolutionBasedThumbnailsConfiguration(width, height, allowEnlarging);
-        imagePyramid.add(imageRep);
-        return imageRep;
-    }
-
-    /** the maximal width and height of the generated thumbnails */
-    public void setMaxThumbnailWidthAndHeight(int maxThumbnailWidthAndHeight)
-    {
-        this.maxThumbnailWidthAndHeight = maxThumbnailWidthAndHeight;
-    }
-
-    /**
-     * Valid only if thumbnails generation is switched on. Set it to a value lower than 1 if you
-     * want only some of your processor cores to be used for thumbnails generation. Number of
-     * threads that are used for thumbnail generation will be equal to: this constant * number of
-     * processor cores.
-     */
-    public void setAllowedMachineLoadDuringThumbnailsGeneration(
-            double allowedMachineLoadDuringThumbnailsGeneration)
-    {
-        this.allowedMachineLoadDuringThumbnailsGeneration =
-                allowedMachineLoadDuringThumbnailsGeneration;
-    }
-
-    /**
-     * Decides if ImageMagic 'convert' utility will be used to generate thumbnails. True by default.
-     * <p>
-     * One should set this option to false and use the internal library if 'convert' tool is not
-     * installed or if many images are stored in one image container file.
-     */
-    public void setUseImageMagicToGenerateThumbnails(boolean generateWithImageMagic)
-    {
-        this.generateThumbnailsWithImageMagic = generateWithImageMagic;
-    }
-
-    public boolean getGenerateThumbnailsWithImageMagic()
-    {
-        return generateThumbnailsWithImageMagic;
-    }
-
-    /**
-     * Sets additional parameters which should be passed to ImageMagic 'convert' utility when it is
-     * used to generate thumbnails.
-     * <p>
-     * Example: pass "-contrast-stretch 2%" to discard 2% of brightest and darkest pixels in the
-     * thumbnails.
-     */
-    public void setThumbnailsGenerationImageMagicParams(String[] imageMagicParams)
-    {
-        this.thumbnailsGenerationImageMagicParams = Arrays.asList(imageMagicParams);
-    }
-
-    public List<String> getThumbnailsGenerationImageMagicParams()
-    {
-        return thumbnailsGenerationImageMagicParams;
-    }
-
-    /**
-     * If true and thumbnails generation is switched on, thumbnails will be generated with high
-     * quality.
-     * <p>
-     * Be careful: high quality means that the generation will take longer and the image will be
-     * converted to 8 bit color depth. This option is useful for segmentation images, images with 8
-     * bit color depth or when no 16 bit transformation has to be applied to the images.
-     */
-    public void setGenerateHighQuality8BitThumbnails(boolean highQualityThumbnails)
-    {
-        this.generateThumbnailsIn8BitHighQuality = highQualityThumbnails;
-    }
-
-    public boolean getGenerateThumbnailsIn8BitHighQuality()
-    {
-        return generateThumbnailsIn8BitHighQuality;
-    }
-
-    /**
-     * See {@link #setGenerateHighQuality8BitThumbnails}.
-     * 
-     * @deprecated use {@link #setGenerateHighQuality8BitThumbnails} instead.
-     */
-    @Deprecated
-    public void setGenerateHighQualityThumbnails(boolean highQualityThumbnails)
-    {
-        this.generateThumbnailsIn8BitHighQuality = highQualityThumbnails;
-    }
-
-    /**
-     * <p>
-     * Can be used only for grayscale images, Useful when images do not use the whole available
-     * color depth of the format in which they are stored (e.g. 10 bits out of 12). By default
-     * switched off. Causes that the conversion to 8 bit color depth looses less information. At the
-     * same time allows to compare images of one dataset to each other.<br>
-     * Warning: causes that all images have to be analysed before registration, this is a costly
-     * operation!
-     * </p>
-     * <p>
-     * If isComputed is set to true all dataset images will be analysed and one range of pixel
-     * intensities used across all images will be computed (with 0.5% threshold). The result will be
-     * saved and it will be possible to apply on-the-fly transformation when browsing images.
-     * </p>
-     * <p>
-     * Example: let's assume that all plate images are saved as 12 bit grayscales. Each image has
-     * ability to use pixel intensities from 0 to 4095. In our example only a range of the available
-     * intensities is used, let's say from 1024 to 2048. Before the image is displayed to the user
-     * it has to be converted to 8-bit color depth (range of intensities from 0 to 255). Without
-     * taking the effectively used intensities into account the range 1024...2048 would be converted
-     * to a range of 64..128 and other intensities would be unused. Analysing the images allows to
-     * convert 1024...2048 range to the full 0..255 range.
-     * </p>
-     */
-    public void setComputeCommonIntensityRangeOfAllImagesForAllChannels()
-    {
-        this.computeCommonIntensityRangeOfAllImagesForChannelsOrNull = Collections.emptyList();
-    }
-
-    /**
-     * See {@link #setComputeCommonIntensityRangeOfAllImagesForAllChannels()}.
-     * 
-     * @param channelCodesOrNull list of channel codes for which the optimal intensity rescaling
-     *            parameters will be computed. If empty all channels will be analysed. If null
-     *            nothing will be analysed (default behavior).
-     */
-    public void setComputeCommonIntensityRangeOfAllImagesForChannels(String[] channelCodesOrNull)
-    {
-        this.computeCommonIntensityRangeOfAllImagesForChannelsOrNull =
-                Arrays.asList(channelCodesOrNull);
-    }
-
-    /**
-     * Set the label of the transformation which will rescale dataset images intensities in an
-     * optimal and comparable way. Can be used if the default value is not appropriate.
-     * <p>
-     * See {@link #setComputeCommonIntensityRangeOfAllImagesForAllChannels()} for details.
-     */
-    public void setComputeCommonIntensityRangeOfAllImagesLabel(
-            String userFriendlyTransformationlabel)
-    {
-        this.computeCommonIntensityRangeOfAllImagesLabel = userFriendlyTransformationlabel;
-    }
-
-    /**
-     * Sets the threshold of intensities which should be ignored when computing common intensity
-     * range of all images. By default equal to 0.5%. Note that
-     * {@link #setComputeCommonIntensityRangeOfAllImagesForAllChannels()} or
-     * {@link #setComputeCommonIntensityRangeOfAllImagesForChannels(String[])} has to be called to
-     * switch on analysis.
-     * 
-     * @param threshold value from 0 to 1. If set to e.g. 0.1 then 10% of brightest and darkest
-     *            pixels will be ignored.
-     */
-    public void setComputeCommonIntensityRangeOfAllImagesThreshold(float threshold)
-    {
-        this.computeCommonIntensityRangeOfAllImagesThreshold = threshold;
-    }
-
-    /**
-     * Sets fixed levels for the common intensity range transformation for all images. If this one
-     * is set, the automatic level computation is switched off which may give big performance
-     * improvements. If the method
-     * {@link #setComputeCommonIntensityRangeOfAllImagesForChannels(String[])} is not called, will
-     * set the transformation for all channels.
-     */
-    public void setDefaultFixedIntensityRangeForAllImages(int minLevel, int maxLevel)
-    {
-        if (fixedIntensityRangeForAllImages == null)
-        {
-            fixedIntensityRangeForAllImages = new HashMap<String, IntensityRange>();
-        }
-        this.fixedIntensityRangeForAllImages.put(null, new IntensityRange(minLevel, maxLevel));
-    }
-
-    /**
-     * Add fixed levels for the common intensity range transformation of the given cannel for all
-     * images. If this one is set, the automatic level computation is switched off which can give
-     * big performance improvements.
-     * <p>
-     * Note: If {@link #setDefaultFixedIntensityRangeForAllImages(int, int)} is called as well, then
-     * the values provided here will overwrite the default values provided there for the channel
-     * <var>channelCode</var>. Otherwise, the common intensity transformation will only be computed
-     * for the channels where the levels have been set explicitly by this method.
-     */
-    public void addFixedIntensityRangeForAllImages(String channelCode, int minLevel, int maxLevel)
-    {
-        if (fixedIntensityRangeForAllImages == null)
-        {
-            fixedIntensityRangeForAllImages = new HashMap<String, IntensityRange>();
-        }
-        this.fixedIntensityRangeForAllImages.put(CodeNormalizer.normalize(channelCode),
-                new IntensityRange(minLevel, maxLevel));
-    }
-
-    /**
-     * Sets if the image transformation using common intensity range of all images should be the
-     * default choice when browsing images.
-     * <p>
-     * True by default, which means e.g. that the 'image optimal' transformation will not be
-     * automatically available for users. However one can still add it explicitly with a chosen
-     * threshold by redefining
-     * {@link SimpleImageDataConfig#getAvailableChannelTransformations(String)} method.
-     */
-    public void setComputeCommonIntensityRangeOfAllImagesIsDefault(boolean isDefault)
-    {
-        this.computeCommonIntensityRangeOfAllImagesIsDefault = isDefault;
-    }
-
-    /** Should all dataset in one experiment use the same channels? By default set to false. */
-    public void setStoreChannelsOnExperimentLevel(boolean storeChannelsOnExperimentLevel)
-    {
-        this.storeChannelsOnExperimentLevel = storeChannelsOnExperimentLevel;
-    }
-
-    /**
-     * Should the original data be stored in the original form or should we pack them into one
-     * container? Available values are {@link OriginalDataStorageFormat#UNCHANGED},
-     * {@link OriginalDataStorageFormat#HDF5}, {@link OriginalDataStorageFormat#HDF5_COMPRESSED}.
-     * The default is {@link OriginalDataStorageFormat#UNCHANGED}.
-     */
-    public void setOriginalDataStorageFormat(OriginalDataStorageFormat originalDataStorageFormat)
-    {
-        this.originalDataStorageFormat = originalDataStorageFormat;
-    }
-
-    /**
-     * Sets parameters for the 'convert' command line tool, which will be used to apply an image
-     * transformation on the fly when an image is fetched.
-     */
-    public void setConvertTransformationCliArguments(String convertTransformationCliArguments)
-    {
-        this.convertTransformationCliArgumentsOrNull = convertTransformationCliArguments;
-    }
-
-    /**
-     * Which image library and reader should be used to read the image? <br>
-     * Available libraries [readers]:<br>
-     * - IJ: [tiff]<br>
-     * - ImageIO: [jpg, bmp, jpeg, wbmp, png, gif]<br>
-     * - JAI: [pnm, jpeg, fpx, gif, tiff, wbmp, png, bmp]<br>
-     * - BioFormats: [ZipReader, APNGReader, JPEGReader, PGMReader, FitsReader, PCXReader,
-     * GIFReader, BMPReader, IPLabReader, IvisionReader, DeltavisionReader, MRCReader, GatanReader,
-     * GatanDM2Reader, ImarisReader, OpenlabRawReader, OMEXMLReader, LIFReader, AVIReader,
-     * PictReader, SDTReader, EPSReader, SlidebookReader, AliconaReader, MNGReader, KhorosReader,
-     * VisitechReader, LIMReader, PSDReader, InCellReader, L2DReader, FEIReader, NAFReader,
-     * MINCReader, QTReader, MRWReader, TillVisionReader, ARFReader, CellomicsReader, LiFlimReader,
-     * TargaReader, OxfordInstrumentsReader, VGSAMReader, HISReader, WATOPReader, SeikoReader,
-     * TopometrixReader, UBMReader, QuesantReader, BioRadGelReader, RHKReader,
-     * MolecularImagingReader, CellWorxReader, Ecat7Reader, VarianFDFReader, AIMReader, FakeReader,
-     * JEOLReader, NiftiReader, AnalyzeReader, APLReader, NRRDReader, ICSReader, PerkinElmerReader,
-     * AmiraReader, ScanrReader, BDReader, UnisokuReader, PDSReader, BioRadReader, FV1000Reader,
-     * ZeissZVIReader, IPWReader, ND2Reader, JPEG2000Reader, PCIReader, ImarisHDFReader,
-     * ZeissLSMReader, SEQReader, GelReader, ImarisTiffReader, FlexReader, SVSReader, ImaconReader,
-     * LEOReader, JPKReader, MIASReader, TCSReader, LeicaReader, NikonReader, FluoviewReader,
-     * PrairieReader, MetamorphReader, MicromanagerReader, ImprovisionTiffReader,
-     * MetamorphTiffReader, NikonTiffReader, OMETiffReader, PhotoshopTiffReader, FEITiffReader,
-     * SimplePCITiffReader, NikonElementsTiffReader, TiffDelegateReader, TextReader, BurleighReader,
-     * OpenlabReader, DicomReader, SMCameraReader, SBIGReader]
-     */
-    public void setImageLibrary(String imageLibraryName, String readerName)
-    {
-        this.imageLibraryInfoOrNull = new ImageLibraryInfo(imageLibraryName, readerName);
-    }
-
-    /**
-     * Sets the image library to be used for reading images. Available libraries are: IJ, ImageIO,
-     * JAI, and BioFormats. The first image file is used to determine the actual reader. Note, that
-     * all images are read with the same image reader.
-     */
-    public void setImageLibrary(String imageLibraryName)
-    {
-        this.imageLibraryInfoOrNull = new ImageLibraryInfo(imageLibraryName);
-    }
-
-    // --- predefined image dataset types
-
-    /**
-     * Sets dataset type to the one which should be used for storing raw images. Marks the dataset
-     * as a "measured" one.
-     */
-    public void setRawImageDatasetType()
-    {
-        setDataSetType(ScreeningConstants.DEFAULT_RAW_IMAGE_DATASET_TYPE);
-        setMeasuredData(true);
-    }
-
-    /**
-     * Sets dataset type to the one which should be used for storing overview images generated from
-     * raw images. Marks the dataset as a "derived" one.
-     */
-    public void setOverviewImageDatasetType()
-    {
-        setDataSetType(ScreeningConstants.DEFAULT_OVERVIEW_IMAGE_DATASET_TYPE);
-        setMeasuredData(false);
-    }
-
-    /**
-     * Sets dataset type to the one which should be used for storing overlay images. Marks the
-     * dataset as a "derived" one.
-     */
-    public void setSegmentationImageDatasetType()
-    {
-        setDataSetType(ScreeningConstants.DEFAULT_SEGMENTATION_IMAGE_DATASET_TYPE);
-        setMeasuredData(false);
-    }
-
-    // --- standard
-
-    /** Sets the type of the dataset. */
-    public void setDataSetType(String datasetTypeCode)
-    {
-        this.mainDatasetTypeCode = datasetTypeCode;
-    }
-
-    /** Sets the file type of the dataset. */
-    public void setFileFormatType(String fileFormatCode)
-    {
-        this.fileFormatCode = fileFormatCode;
-    }
-
-    /**
-     * Set whether the data is measured or not. By default false.
-     */
-    public void setMeasuredData(boolean isMeasured)
-    {
-        this.isMeasured = isMeasured;
-    }
-
-    /**
-     * Sets the microscopy flag which is by default <code>false</code>. This flag is used to check
-     * whether well in {@link ImageMetadata} is specified or not. In case of microscopy well is
-     * ignored. Otherwise it is mandatory.
-     */
-    public void setMicroscopyData(boolean isMicroscopy)
-    {
-        this.isMicroscopy = isMicroscopy;
-    }
-
-    public String getDataSetType()
-    {
-        return mainDatasetTypeCode;
-    }
-
-    public String getFileFormatType()
-    {
-        return fileFormatCode;
-    }
-
-    public boolean isMeasuredData()
-    {
-        return isMeasured;
-    }
-
-    public boolean isMicroscopyData()
-    {
-        return isMicroscopy;
-    }
-
-    public void setThumbnailsFileFormat(String thumbnailsFileFormat)
-    {
-        this.thumbnailsFileFormat = thumbnailsFileFormat;
-    }
-
-    public String getThumbnailsFileFormat()
-    {
-        return this.thumbnailsFileFormat;
-    }
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleOverviewImageDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleOverviewImageDataConfig.java
index 3fe34cf61299aae241ece223042ef454e6760b46..f6d3a3f9db57c184c8e039907df7689720f221dc 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleOverviewImageDataConfig.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleOverviewImageDataConfig.java
@@ -17,35 +17,12 @@
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
 /**
- * * Allows to configure extraction of overview images for a plate or microscopy sample.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleOverviewImageDataConfig} instead
  * 
- * @author Pawel Glyzewski
+ * @author Jakub Straszewski
  */
-public class SimpleOverviewImageDataConfig extends SimpleImageDataConfig
+public class SimpleOverviewImageDataConfig extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleOverviewImageDataConfig
 {
-    private String containerDataSetCode;
-
-    private boolean generateOverviewImagesFromRegisteredImages;
-
-    public String getContainerDataSetCode()
-    {
-        return containerDataSetCode;
-    }
-
-    public void setContainerDataSetCode(String containerDataSetCode)
-    {
-        this.containerDataSetCode = containerDataSetCode;
-    }
-
-    public boolean isGenerateOverviewImagesFromRegisteredImages()
-    {
-        return generateOverviewImagesFromRegisteredImages;
-    }
-
-    public void setGenerateOverviewImagesFromRegisteredImages(
-            boolean generateOverviewImagesFromRegisteredImages)
-    {
-        this.generateOverviewImagesFromRegisteredImages =
-                generateOverviewImagesFromRegisteredImages;
-    }
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ThumbnailsStorageFormat.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ThumbnailsStorageFormat.java
index a9fc82c84b2d7bfb5c6b257bf5752fb51e5a7717..53e40f036110c3b850d75a33eff3052fcc74f907 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ThumbnailsStorageFormat.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ThumbnailsStorageFormat.java
@@ -16,317 +16,15 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
-import java.awt.image.BufferedImage;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import ch.systemsx.cisd.common.reflection.AbstractHashable;
-import ch.systemsx.cisd.openbis.dss.Constants;
-import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
-
 /**
- * Configuration parameters which describe how thumbnails should be generated.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public class ThumbnailsStorageFormat extends AbstractHashable implements Serializable
+public class ThumbnailsStorageFormat extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat
 {
 
     private static final long serialVersionUID = 1L;
-
-    public enum FileFormat
-    {
-        PNG
-        {
-            @Override
-            public void writeImage(BufferedImage image, OutputStream stream)
-            {
-                ImageUtil.writeImageToPng(image, stream);
-            }
-
-            @Override
-            public String getFileExtension()
-            {
-                return "png";
-            }
-
-            @Override
-            public String getImageMagickParam()
-            {
-                return "png";
-            }
-        },
-        JPEG
-        {
-            @Override
-            public void writeImage(BufferedImage image, OutputStream stream)
-            {
-                ImageUtil.writeImageUsingImageIO(image, stream, "jpg");
-            }
-
-            @Override
-            public String getFileExtension()
-            {
-                return "jpg";
-            }
-
-            @Override
-            public String getImageMagickParam()
-            {
-                return "jpeg";
-            }
-        },
-        JPEG_2000
-        {
-            @Override
-            public void writeImage(BufferedImage image, OutputStream stream)
-            {
-                ImageUtil.writeImageUsingImageIO(image, stream, "jpeg 2000");
-            }
-
-            @Override
-            public String getFileExtension()
-            {
-                return "jp2";
-            }
-
-            @Override
-            public String getImageMagickParam()
-            {
-                return "jp2";
-            }
-        };
-
-        private static final Map<String, FileFormat> formats;
-        static
-        {
-            formats = new HashMap<String, ThumbnailsStorageFormat.FileFormat>();
-            for (FileFormat format : FileFormat.values())
-            {
-                formats.put(format.name().toUpperCase(), format);
-            }
-            formats.put("JP2", JPEG_2000);
-            formats.put("JPEG 2000", JPEG_2000);
-            formats.put("JPG", JPEG);
-        }
-
-        public abstract void writeImage(BufferedImage image, OutputStream stream);
-
-        public abstract String getFileExtension();
-
-        public abstract String getImageMagickParam();
-
-        public String getOpenBISFileType()
-        {
-            return getFileExtension().toUpperCase();
-        }
-
-        public static FileFormat getValue(String fileFormat)
-        {
-            return formats.get(fileFormat.toUpperCase());
-        }
-    }
-
-    /** Maximum default width and height of a thumbnail */
-    public static final int DEFAULT_THUMBNAIL_MAX_SIZE = 200;
-
-    /** Maximum default width and height of a thumbnail */
-    public static final boolean DEFAULT_COMPRESS_THUMBNAILS = false;
-
-    // ---
-
-    private int maxWidth = DEFAULT_THUMBNAIL_MAX_SIZE;
-
-    private int maxHeight = DEFAULT_THUMBNAIL_MAX_SIZE;
-
-    private boolean allowEnlarging = true;
-
-    private Double zoomLevel = null;
-
-    private boolean storeCompressed = DEFAULT_COMPRESS_THUMBNAILS;
-
-    private double allowedMachineLoadDuringGeneration = 1;
-
-    private boolean highQuality8Bit = false;
-
-    private boolean generateWithImageMagic = false;
-
-    private List<String> imageMagicParams = Collections.emptyList();
-
-    private String thumbnailsFileName;
-
-    private FileFormat fileFormat = FileFormat.PNG;
-
-    private final Map<String, String> transformations = new HashMap<String, String>();
-
-    /**
-     * Creates empty object which instructs that the thumbnails should be generated with default
-     * settings. Use setters to change default behaviour (you will probably not have to).
-     */
-    public ThumbnailsStorageFormat()
-    {
-    }
-
-    public int getMaxWidth()
-    {
-        return maxWidth;
-    }
-
-    public int getMaxHeight()
-    {
-        return maxHeight;
-    }
-
-    public boolean isStoreCompressed()
-    {
-        return storeCompressed;
-    }
-
-    public double getAllowedMachineLoadDuringGeneration()
-    {
-        return allowedMachineLoadDuringGeneration;
-    }
-
-    public boolean isHighQuality()
-    {
-        return highQuality8Bit;
-    }
-
-    public boolean isGenerateWithImageMagic()
-    {
-        return generateWithImageMagic;
-    }
-
-    public List<String> getImageMagicParams()
-    {
-        return imageMagicParams;
-    }
-
-    public boolean isAllowEnlarging()
-    {
-        return allowEnlarging;
-    }
-
-    // --- setters ---
-
-    /** Sets the maximum width of a thumbnail. */
-    public void setMaxWidth(int maxWidth)
-    {
-        this.maxWidth = maxWidth;
-    }
-
-    /** Sets the maximum height of a thumbnail. */
-    public void setMaxHeight(int maxHeight)
-    {
-        this.maxHeight = maxHeight;
-    }
-
-    /** Sets if each thumbnail should be additionally compressed (lostless) before it is stored. */
-    public void setStoreCompressed(boolean storeCompressed)
-    {
-        this.storeCompressed = storeCompressed;
-    }
-
-    /**
-     * Specify if this image representation is allowed to be larger than the original image.
-     */
-    public void setAllowEnlarging(boolean allowEnlarging)
-    {
-        this.allowEnlarging = allowEnlarging;
-    }
-
-    /**
-     * The number of threads which will be used during thumbnails generation will be equal to number
-     * of processor cores * machineLoad.
-     */
-    public void setAllowedMachineLoadDuringGeneration(double machineLoad)
-    {
-        this.allowedMachineLoadDuringGeneration = machineLoad;
-    }
-
-    /**
-     * Set to true if you want your thumbnails to be of higher quality. In such a case thumbnails
-     * generation during dataset registration will take longer. Recommended for overlay images.
-     */
-    public void setHighQuality(boolean highQuality)
-    {
-        this.highQuality8Bit = highQuality;
-    }
-
-    /**
-     * if true ImageMagic 'convert' utility should be installed and will be used to generate
-     * thumbnails. <br>
-     * Note: if images should be handled with a specific image library, it will be ignored for
-     * thumbnails generation if 'convert' is supposed to be used. Make sure that 'convert' can deal
-     * with your images in such a case.
-     */
-    public void setGenerateWithImageMagic(boolean generateWithImageMagic)
-    {
-        this.generateWithImageMagic = generateWithImageMagic;
-    }
-
-    /**
-     * Sets additional parameters which should be passed to ImageMagic 'convert' utility when it is
-     * used to generate thumbnails. Example: pass "-contrast-stretch 2%" to discard 2% of brightest
-     * and darkest pixels in the thumbnails.
-     */
-    public void setImageMagicParams(List<String> imageMagicParams)
-    {
-        this.imageMagicParams = imageMagicParams;
-    }
-
-    public Double getZoomLevel()
-    {
-        return zoomLevel;
-    }
-
-    public void setZoomLevel(Double zoomLevel)
-    {
-        this.zoomLevel = zoomLevel;
-    }
-
-    public String getThumbnailsFileName()
-    {
-        return thumbnailsFileName == null ? Constants.HDF5_CONTAINER_THUMBNAILS_FILE_NAME
-                : thumbnailsFileName;
-    }
-
-    public void setThumbnailsFileName(String thumbnailsFileName)
-    {
-        this.thumbnailsFileName = thumbnailsFileName;
-    }
-
-    public void setFileFormat(String fileFormat)
-    {
-        FileFormat value = FileFormat.getValue(fileFormat);
-        if (value == null)
-        {
-            throw new IllegalArgumentException("File format '" + fileFormat + "' is unknown");
-        }
-        this.fileFormat = value;
-    }
-
-    public FileFormat getFileFormat()
-    {
-        return fileFormat;
-    }
-
-    public void setTransformations(Map<String, String> transformations)
-    {
-        this.transformations.putAll(transformations);
-    }
-
-    public String getTransformationCode(String channelCode)
-    {
-        return transformations.get(channelCode.toUpperCase());
-    }
-
-    public Map<String, String> getTransformations()
-    {
-        return transformations;
-    }
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorContainerDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/FeatureVectorContainerDataSet.java
similarity index 97%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorContainerDataSet.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/FeatureVectorContainerDataSet.java
index 39fc5a09711862de1692e4fe90e343569fe5814b..4107b3b13cb44a6560f03e639821a80c8e1ef711 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorContainerDataSet.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/FeatureVectorContainerDataSet.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl;
 
 import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.ANALYSIS_PROCEDURE;
 
@@ -24,7 +24,7 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSet;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IFeatureVectorDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeatureVectorDataSet;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IExperimentImmutable;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.ISampleImmutable;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/FeatureVectorDataSet.java
similarity index 96%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSet.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/FeatureVectorDataSet.java
index 0597293943e8008b78a56259e3ae8c2938ef3ea7..f432b51b95de3d34a4a813164044efbdce668783 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSet.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/FeatureVectorDataSet.java
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl;
 
 import java.io.File;
 import java.util.List;
 
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSet;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IFeatureVectorDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeatureVectorDataSet;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IDataSetImmutable;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IExperimentImmutable;
@@ -30,8 +31,6 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.ISampleImmuta
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSetType;
 
 /**
- * 
- *
  * @author Franz-Josef Elmer
  */
 public class FeatureVectorDataSet extends DataSet<FeatureVectorDataSetInformation> implements
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageContainerDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/ImageContainerDataSet.java
similarity index 97%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageContainerDataSet.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/ImageContainerDataSet.java
index 20944b729310f5aca62374767b5494732a0b8772..0c29e2bb6b284f1e35267fc359a803e130363a7d 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageContainerDataSet.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/impl/ImageContainerDataSet.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl;
 
 import java.io.File;
 import java.util.Collections;
@@ -24,6 +24,7 @@ import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSet;
 import ch.systemsx.cisd.openbis.dss.etl.PlateGeometryOracle;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IImageDataSet;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IExperimentImmutable;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/AbstractThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/AbstractThumbnailsConfiguration.java
index f034defe2e45f5192fd9a079c9ee25163f5f4808..310d4e93c1a7a7845d46ed043a187576c0a994cb 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/AbstractThumbnailsConfiguration.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/AbstractThumbnailsConfiguration.java
@@ -16,97 +16,14 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails;
 
-import java.util.HashMap;
-import java.util.Map;
-
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
-
 /**
- * @author Pawel Glyzewski
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.AbstractThumbnailsConfiguration}
+ * instead
+ * 
+ * @author Jakub Straszewski
  */
-public abstract class AbstractThumbnailsConfiguration implements IThumbnailsConfiguration
+public abstract class AbstractThumbnailsConfiguration extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.AbstractThumbnailsConfiguration
 {
-    private String fileName;
-
-    private String fileFormat;
-
-    private Map<String, String> transformations = new HashMap<String, String>();
-
-    @Override
-    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config)
-    {
-        ThumbnailsStorageFormat thumbnailsStorageFormat = new ThumbnailsStorageFormat();
-        thumbnailsStorageFormat.setAllowedMachineLoadDuringGeneration(config
-                .getAllowedMachineLoadDuringThumbnailsGeneration());
-        thumbnailsStorageFormat.setThumbnailsFileName(getFileName());
-        thumbnailsStorageFormat.setMaxWidth(config.getMaxThumbnailWidthAndHeight());
-        thumbnailsStorageFormat.setMaxHeight(config.getMaxThumbnailWidthAndHeight());
-        thumbnailsStorageFormat.setGenerateWithImageMagic(config
-                .getGenerateThumbnailsWithImageMagic());
-        thumbnailsStorageFormat.setImageMagicParams(config
-                .getThumbnailsGenerationImageMagicParams());
-        thumbnailsStorageFormat.setHighQuality(config.getGenerateThumbnailsIn8BitHighQuality());
-        setFileFormat(thumbnailsStorageFormat, config.getThumbnailsFileFormat());
-        thumbnailsStorageFormat.setTransformations(transformations);
-        return thumbnailsStorageFormat;
-    }
-
-    protected abstract String getDefaultFileName();
-
-    @Override
-    public void setFileName(String fileName)
-    {
-        this.fileName = fileName;
-    }
-
-    public String getFileName()
-    {
-        if (fileName != null)
-        {
-            return fileName;
-        } else
-        {
-            return getDefaultFileName();
-        }
-    }
-
-    @Override
-    public void setFileFormat(String fileFormat)
-    {
-        this.fileFormat = fileFormat;
-    }
-
-    public String getFileFormat()
-    {
-        return this.fileFormat;
-    }
-
-    private void setFileFormat(ThumbnailsStorageFormat thumbnailsStorageFormat, String defaultValue)
-    {
-        if (fileFormat != null)
-        {
-            thumbnailsStorageFormat.setFileFormat(fileFormat);
-        } else if (defaultValue != null)
-        {
-            thumbnailsStorageFormat.setFileFormat(defaultValue);
-        }
-    }
-
-    @Override
-    public String setTransformation(String channelCode, String transformationCode)
-    {
-        return transformations.put(channelCode.toUpperCase(), transformationCode);
-    }
-
-    protected String getFirstTransformationCode()
-    {
-        if (transformations.size() == 0)
-        {
-            return "";
-        } else
-        {
-            return "_" + transformations.values().iterator().next();
-        }
-    }
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/DefaultThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/DefaultThumbnailsConfiguration.java
index 531b8c8ea962a761091907ab1743cb89a322bc85..f835ac5d0aae67859d46a1c9c1657b11a8e2e4b6 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/DefaultThumbnailsConfiguration.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/DefaultThumbnailsConfiguration.java
@@ -16,16 +16,14 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails;
 
-import ch.systemsx.cisd.openbis.dss.Constants;
-
 /**
- * @author Pawel Glyzewski
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.DefaultThumbnailsConfiguration}
+ * instead
+ * 
+ * @author Jakub Straszewski
  */
-public class DefaultThumbnailsConfiguration extends AbstractThumbnailsConfiguration
+public class DefaultThumbnailsConfiguration extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.DefaultThumbnailsConfiguration
 {
-    @Override
-    protected String getDefaultFileName()
-    {
-        return Constants.HDF5_CONTAINER_THUMBNAILS_FILE_NAME;
-    }
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ResolutionBasedThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ResolutionBasedThumbnailsConfiguration.java
index 4c464ba1ab8f165888af4d26bc1b7973b7f76265..1a255a8ac177d1845fedf57259e913a8b8f84ecb 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ResolutionBasedThumbnailsConfiguration.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ResolutionBasedThumbnailsConfiguration.java
@@ -16,47 +16,25 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails;
 
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
-
 /**
- * @author Pawel Glyzewski
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.ResolutionBasedThumbnailsConfiguration}
+ * instead
+ * 
+ * @author Jakub Straszewski
  */
-public class ResolutionBasedThumbnailsConfiguration extends AbstractThumbnailsConfiguration
+public class ResolutionBasedThumbnailsConfiguration extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.ResolutionBasedThumbnailsConfiguration
 {
-    private final int maxWidth;
-
-    private final int maxHeight;
-
-    private final boolean allowEnlarging;
 
-    public ResolutionBasedThumbnailsConfiguration(int maxWidth, int maxHeight)
-    {
-        this(maxWidth, maxHeight, true);
-    }
-
-    public ResolutionBasedThumbnailsConfiguration(int maxWidth, int maxHeight,
+    private ResolutionBasedThumbnailsConfiguration(int maxWidth, int maxHeight,
             boolean allowEnlarging)
     {
-        this.maxWidth = maxWidth;
-        this.maxHeight = maxHeight;
-        this.allowEnlarging = allowEnlarging;
-    }
-
-    @Override
-    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config)
-    {
-        ThumbnailsStorageFormat thumbnailsStorageFormat = super.getThumbnailsStorageFormat(config);
-        thumbnailsStorageFormat.setMaxWidth(maxWidth);
-        thumbnailsStorageFormat.setMaxHeight(maxHeight);
-        thumbnailsStorageFormat.setAllowEnlarging(allowEnlarging);
-        return thumbnailsStorageFormat;
+        super(maxWidth, maxHeight, allowEnlarging);
     }
 
-    @Override
-    protected String getDefaultFileName()
+    private ResolutionBasedThumbnailsConfiguration(int maxWidth, int maxHeight)
     {
-        return String.format("thumbnails_%dx%d%s.h5ar", maxWidth, maxHeight,
-                getFirstTransformationCode());
+        super(maxWidth, maxHeight);
     }
-}
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java
index 4930e0052fd5e16d81d9467e70081b1a80a9d84c..89bcb1f7ce6083ecb9932d928a69eb96dca11134 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java
@@ -16,33 +16,19 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails;
 
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
-
 /**
- * @author Pawel Glyzewski
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.ZoomLevelBasedThumbnailsConfiguration}
+ * instead
+ * 
+ * @author Jakub Straszewski
  */
-public class ZoomLevelBasedThumbnailsConfiguration extends AbstractThumbnailsConfiguration
+public class ZoomLevelBasedThumbnailsConfiguration extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.thumbnails.ZoomLevelBasedThumbnailsConfiguration
 {
-    private final double zoomLevel;
-
-    public ZoomLevelBasedThumbnailsConfiguration(double zoomLevel)
-    {
-        this.zoomLevel = zoomLevel;
-    }
-
-    @Override
-    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config)
-    {
-        ThumbnailsStorageFormat thumbnailsStorageFormat = super.getThumbnailsStorageFormat(config);
-        thumbnailsStorageFormat.setZoomLevel(zoomLevel);
-        return thumbnailsStorageFormat;
-    }
 
-    @Override
-    protected String getDefaultFileName()
+    private ZoomLevelBasedThumbnailsConfiguration(double zoomLevel)
     {
-        return String.format("thumbnails_%.0fpct%s.h5ar", zoomLevel * 100.0,
-                getFirstTransformationCode());
+        super(zoomLevel);
     }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/AutoRescaleIntensityImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/AutoRescaleIntensityImageTransformerFactory.java
index fa5b8cba044597275159b834df3a795b879e4077..831d4c40b7cebeb340c116a593cd989d11c8b1c6 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/AutoRescaleIntensityImageTransformerFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/AutoRescaleIntensityImageTransformerFactory.java
@@ -16,54 +16,22 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
 
-import java.awt.image.BufferedImage;
-
-
-import ch.systemsx.cisd.base.image.IImageTransformer;
-import ch.systemsx.cisd.base.image.IImageTransformerFactory;
-import ch.systemsx.cisd.base.annotation.JsonObject;
-import ch.systemsx.cisd.common.image.IntensityRescaling;
-import ch.systemsx.cisd.common.image.IntensityRescaling.Levels;
-
 /**
- * Transformation performed by
- * {@link IntensityRescaling#rescaleIntensityLevelTo8Bits(BufferedImage, Levels)} where levels are
- * computed automatically by {@link IntensityRescaling#computeLevels(BufferedImage, float)}.
- * <p>
- * Warning: The serialized version of this class can be stored in the database for each image.
- * Moving this class to a different package or changing it in a backward incompatible way would make
- * all the saved transformations invalid.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.AutoRescaleIntensityImageTransformerFactory}
+ * instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-@JsonObject("AutoRescaleIntensityImageTransformerFactory")
-public class AutoRescaleIntensityImageTransformerFactory implements IImageTransformerFactory
+public class AutoRescaleIntensityImageTransformerFactory
+        extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.AutoRescaleIntensityImageTransformerFactory
 {
     private static final long serialVersionUID = 1L;
 
-    private final float threshold;
-
     public AutoRescaleIntensityImageTransformerFactory(float threshold)
     {
-        this.threshold = threshold;
-    }
-
-    @Override
-    public IImageTransformer createTransformer()
-    {
-        return new IImageTransformer()
-            {
-                @Override
-                public BufferedImage transform(BufferedImage image)
-                {
-                    if (IntensityRescaling.isNotGrayscale(image))
-                    {
-                        return image;
-                    }
-                    Levels levels = IntensityRescaling.computeLevels(image, threshold);
-                    return IntensityRescaling.rescaleIntensityLevelTo8Bits(image, levels);
-                }
-            };
+        super(threshold);
     }
 
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformer.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformer.java
index fd2eeac9d7f87488e9623a7bd30c81e721e7976b..5c046ca8dd022e75ef8ea60f0225420725dd51b7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformer.java
@@ -16,254 +16,22 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
 
-import java.awt.image.BufferedImage;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.log4j.Logger;
-
-import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
-import ch.systemsx.cisd.base.image.IStreamingImageTransformer;
-import ch.systemsx.cisd.base.utilities.OSUtilities;
-import ch.systemsx.cisd.common.concurrent.ConcurrencyUtilities;
-import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
-import ch.systemsx.cisd.common.logging.LogCategory;
-import ch.systemsx.cisd.common.logging.LogFactory;
-import ch.systemsx.cisd.common.process.IProcessIOHandler;
-import ch.systemsx.cisd.common.process.ProcessExecutionHelper;
-import ch.systemsx.cisd.common.process.ProcessIOStrategy;
-import ch.systemsx.cisd.common.process.ProcessResult;
-import ch.systemsx.cisd.imagereaders.IImageReader;
-import ch.systemsx.cisd.imagereaders.ImageID;
-import ch.systemsx.cisd.imagereaders.ImageReaderConstants;
-import ch.systemsx.cisd.imagereaders.ImageReaderFactory;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ConvertToolImageTransformerFactory.ToolChoice;
-import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ConvertToolImageTransformerFactory.ToolChoice;
 
 /**
- * An {@link IStreamingImageTransformer} using the convert command line tool for transformations.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ConvertToolImageTransformer}
+ * instead
  * 
- * @author Kaloyan Enimanev
+ * @author Jakub Straszewski
  */
-public class ConvertToolImageTransformer implements IStreamingImageTransformer
+public class ConvertToolImageTransformer extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ConvertToolImageTransformer
 {
 
-    private static final String PNG = "png";
-
-    private static final File imageMagickConvertUtilityOrNull;
-
-    private static final File graphicsMagickUtilityOrNull;
-
-    static
-    {
-        imageMagickConvertUtilityOrNull = OSUtilities.findExecutable("convert");
-        graphicsMagickUtilityOrNull = OSUtilities.findExecutable("gm");
-        if (imageMagickConvertUtilityOrNull == null && graphicsMagickUtilityOrNull == null)
-        {
-            throw new ConfigurationFailureException(
-                    "Neither ImageMagick 'convert' nor GraphisMagick 'gm' can be found"
-                            + " on the system path. Requested image transformation is not available.");
-        }
-    }
-
-    private static final Logger machineLog = LogFactory.getLogger(LogCategory.MACHINE,
-            ConvertToolImageTransformer.class);
-
-    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
-            ConvertToolImageTransformer.class);
-
-    private final byte[] buffer = new byte[ProcessExecutionHelper.RECOMMENDED_BUFFER_SIZE];
-
-    private final List<String> convertCliArguments;
-
-    private final boolean useGraphicsMagic;
-
     ConvertToolImageTransformer(String arguments, ToolChoice choiceOrNull)
     {
-        this.convertCliArguments = parseCommandArguments(arguments);
-        ToolChoice choice = (choiceOrNull == null ? ToolChoice.ENFORCE_IMAGEMAGICK : choiceOrNull);
-        switch (choice)
-        {
-            case ENFORCE_IMAGEMAGICK:
-                if (imageMagickConvertUtilityOrNull == null)
-                {
-                    throw new ConfigurationFailureException(
-                            "The ImageMagick 'convert' tool cannot be found on the system path."
-                                    + " Requested image transformation is not available.");
-                }
-                useGraphicsMagic = false;
-                break;
-            case ENFORCE_GRAPHICSMAGICK:
-                if (graphicsMagickUtilityOrNull == null)
-                {
-                    throw new ConfigurationFailureException(
-                            "The GraphicsMagic 'gm' tool cannot be found on the system path."
-                                    + " Requested image transformation is not available.");
-                }
-                useGraphicsMagic = true;
-                break;
-            case PREFER_IMAGEMAGICK:
-                useGraphicsMagic = (imageMagickConvertUtilityOrNull == null);
-                break;
-            case PREFER_GRAPHICSMAGICK:
-                useGraphicsMagic = (graphicsMagickUtilityOrNull != null);
-                break;
-            default:
-                throw new Error("Unknown ToolChoice " + choice + ".");
-        }
-    }
-
-    @Override
-    public BufferedImage transform(BufferedImage image)
-    {
-        try
-        {
-            byte[] input = ImageUtil.imageToPngFast(image);
-            byte[] output = transform(input);
-            return toBufferedImage(output);
-        } catch (IOException ioex)
-        {
-            throw CheckedExceptionTunnel.wrapIfNecessary(ioex);
-        }
-    }
-
-    @Override
-    public BufferedImage transform(InputStream input)
-    {
-        return toBufferedImage(transformToPNG(input));
-    }
-
-    @Override
-    public byte[] transformToPNG(InputStream input)
-    {
-        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        transformToPNGStream(input, bos);
-        return bos.toByteArray();
-    }
-
-    @Override
-    public void transformToPNGStream(InputStream input, OutputStream output)
-    {
-        try
-        {
-            transform(input, output);
-        } catch (IOException ioex)
-        {
-            throw CheckedExceptionTunnel.wrapIfNecessary(ioex);
-        }
-    }
-
-    private BufferedImage toBufferedImage(byte[] output) throws ConfigurationFailureException
-    {
-        IImageReader imageReader =
-                ImageReaderFactory.tryGetReader(ImageReaderConstants.IMAGEIO_LIBRARY, PNG);
-        if (imageReader == null)
-        {
-            throw new ConfigurationFailureException("No ImageIO image readers available");
-        }
-        return imageReader.readImage(output, ImageID.NULL, null);
-    }
-
-    private byte[] transform(final byte[] input) throws IOException
-    {
-        final ByteArrayInputStream bis = new ByteArrayInputStream(input);
-        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        transform(bis, bos);
-        return bos.toByteArray();
-    }
-
-    private void transform(final InputStream input, final OutputStream output) throws IOException
-    {
-
-        final List<String> errorLines = new ArrayList<String>();
-        ProcessIOStrategy customIOStrategy =
-                createCustomProcessIOStrategy(input, output, errorLines);
-
-        ProcessResult result =
-                ProcessExecutionHelper.run(getCommandLine(), operationLog, machineLog,
-                        ConcurrencyUtilities.NO_TIMEOUT, customIOStrategy, false);
-
-        if (result.isOK() == false)
-        {
-            final String msg =
-                    String.format(
-                            "Error calling '%s'. Exit value: %d, I/O status: %s\nError output: %s",
-                            getCommandLine().toString(), result.getExitValue(), result
-                                    .getProcessIOResult().getStatus(), errorLines.toString());
-            operationLog.warn(msg);
-            throw new IOException(msg);
-        }
-    }
-
-    private ProcessIOStrategy createCustomProcessIOStrategy(final InputStream input,
-            final OutputStream output, final List<String> errorLines)
-    {
-        return ProcessIOStrategy.createCustom(new IProcessIOHandler()
-            {
-
-                @Override
-                public void handle(AtomicBoolean processRunning, OutputStream stdin,
-                        InputStream stdout, InputStream stderr) throws IOException
-                {
-                    int n = 0;
-                    final BufferedReader stdErrReader =
-                            new BufferedReader(new InputStreamReader(stderr));
-                    while (processRunning.get() && (-1 != (n = input.read(buffer))))
-                    {
-                        stdin.write(buffer, 0, n);
-                        ProcessExecutionHelper.readBytesIfAvailable(stdout, output, buffer, -1,
-                                false);
-                        ProcessExecutionHelper.readTextIfAvailable(stdErrReader, errorLines, false);
-                    }
-                    stdin.flush();
-                    stdin.close();
-
-                    while (processRunning.get())
-                    {
-                        ProcessExecutionHelper.readBytesIfAvailable(stdout, output, buffer, -1,
-                                false);
-                        ProcessExecutionHelper.readTextIfAvailable(stdErrReader, errorLines, false);
-                    }
-
-                    ProcessExecutionHelper.readBytesIfAvailable(stdout, output, buffer, -1, false);
-                    ProcessExecutionHelper.readTextIfAvailable(stdErrReader, errorLines, false);
-                }
-            });
-    }
-
-    private List<String> parseCommandArguments(String argsString)
-    {
-        String[] arguments = argsString.trim().split("\\s");
-        return Arrays.asList(arguments);
-    }
-
-    private List<String> getCommandLine()
-    {
-        ArrayList<String> result = new ArrayList<String>();
-        if (useGraphicsMagic)
-        {
-            result.add(graphicsMagickUtilityOrNull.getPath());
-            result.add("convert");
-        } else
-        {
-            result.add(imageMagickConvertUtilityOrNull.getPath());
-        }
-        result.addAll(convertCliArguments);
-        // use standard input to read image
-        result.add("-");
-        // use standard output to produce result
-        result.add("png:-");
-        return result;
+        super(arguments, choiceOrNull);
     }
 
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformerFactory.java
index 99377947d6d0dafe04b4c710c8e3d103b267c158..9b63be17052c007b657a1eff51fca562cdd38e00 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformerFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformerFactory.java
@@ -16,53 +16,26 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
 
-import ch.systemsx.cisd.base.image.IStreamingImageTransformerFactory;
-
 /**
- * A {@link IStreamingImageTransformerFactory} that constructs {@link ConvertToolImageTransformer}
- * instances.
- * <p>
- * Warning: The serialized version of this class can be stored in the database for each image.
- * Moving this class to a different package or changing it in a backward incompatible way would make
- * all the saved transformations invalid.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ConvertToolImageTransformerFactory}
+ * instead
  * 
- * @author Kaloyan Enimanev
+ * @author Jakub Straszewski
  */
-public class ConvertToolImageTransformerFactory implements IStreamingImageTransformerFactory
+public class ConvertToolImageTransformerFactory extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ConvertToolImageTransformerFactory
 {
-    private static final long serialVersionUID = 1L;
-
-    private final String convertCliArguments;
 
-    private final ToolChoice choice;
-
-    /**
-     * An enum to choose which of the two tools, ImageMagick or GraphicsMagick, to prefer or to
-     * enforce.
-     */
-    public enum ToolChoice
-    {
-        ENFORCE_IMAGEMAGICK, ENFORCE_GRAPHICSMAGICK, PREFER_IMAGEMAGICK, PREFER_GRAPHICSMAGICK
-    }
+    private static final long serialVersionUID = 1L;
 
-    /**
-     * Constructs the factory with {@link ToolChoice#PREFER_IMAGEMAGICK}.
-     */
     public ConvertToolImageTransformerFactory(String convertCliArguments)
     {
-        this(convertCliArguments, ToolChoice.ENFORCE_IMAGEMAGICK);
+        super(convertCliArguments);
     }
 
     public ConvertToolImageTransformerFactory(String convertCliArguments, ToolChoice choice)
     {
-        this.convertCliArguments = convertCliArguments;
-        this.choice = choice;
+        super(convertCliArguments, choice);
     }
-
-    @Override
-    public ConvertToolImageTransformer createTransformer()
-    {
-        return new ConvertToolImageTransformer(convertCliArguments, choice);
-    }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformation.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformation.java
index 6c67458d0e8c110a62ea232439eb1b3d9ec1559e..c997281bd2c056528104aeffd41ec441fc974dba 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformation.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformation.java
@@ -16,124 +16,24 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
 
-import java.io.Serializable;
-
 import ch.systemsx.cisd.base.image.IImageTransformerFactory;
-import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
 
 /**
- * Describes image transformation, contains user friendly label and description.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation} instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public class ImageTransformation implements Serializable
+public class ImageTransformation extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation
 {
-    
-    private static final long serialVersionUID = 1L;
-
-    private String code;
-
-    private String label;
-
-    // can be null
-    private String description;
-
-    private boolean isDefault;
 
-    private final IImageTransformerFactory imageTransformerFactory;
-
-    private final boolean isEditable;
+    private static final long serialVersionUID = 1L;
 
     public ImageTransformation(String code, String label, String description,
             IImageTransformerFactory imageTransformerFactory)
     {
-        assert code != null : "code is null";
-        assert label != null : " label is null";
-        assert imageTransformerFactory != null : "imageTransformerFactory is null";
-
-        this.code = CodeNormalizer.normalize(code);
-        this.label = label;
-        this.description = description;
-        this.isDefault = false;
-        this.imageTransformerFactory = imageTransformerFactory;
-        this.isEditable = false; // will be used later for ImageViewer transformations
-    }
-
-    public String getCode()
-    {
-        return code;
-    }
-
-    public String getLabel()
-    {
-        return label;
-    }
-
-    public String getDescription()
-    {
-        return description;
-    }
-
-    public boolean isDefault()
-    {
-        return isDefault;
+        super(code, label, description, imageTransformerFactory);
     }
 
-    public IImageTransformerFactory getImageTransformerFactory()
-    {
-        return imageTransformerFactory;
-    }
-
-    public boolean isEditable()
-    {
-        return isEditable;
-    }
-
-    // ----------- setters
-
-    public void setCode(String code)
-    {
-        this.code = code;
-    }
-
-    public void setLabel(String label)
-    {
-        this.label = label;
-    }
-
-    public void setDescription(String description)
-    {
-        this.description = description;
-    }
-
-    /**
-     * Calling with true makes this transformation a default user's choice and makes the
-     * 'hard-coded' default unavailable. This transformation will become the first one on the list
-     * automatically.
-     * <p>
-     * Marking more then one transformation as a default for one channel will make it impossible to
-     * register a dataset.
-     * </p>
-     * <p>
-     * If no transformation on the list will be marked as default then a 'hard-coded' default
-     * transformation will become available.
-     * </p>
-     */
-    public void setDefault(boolean isDefault)
-    {
-        this.isDefault = isDefault;
-    }
-
-    @Override
-    public String toString()
-    {
-        StringBuffer sb = new StringBuffer();
-        sb.append("ImageTransformation [code=" + code + ", label=" + label);
-        if (description != null)
-        {
-            sb.append(", description=" + description);
-        }
-        sb.append(", isDefault=" + isDefault + "]");
-        return sb.toString();
-    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBuffer.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBuffer.java
index 3d4ff923983d1d297e08c7b3d388c776b9d8e83a..5cac3799a3a327913bbfca91189a99fe3bfaa1d8 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBuffer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBuffer.java
@@ -16,450 +16,14 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
 
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import ch.rinn.restrictions.Private;
-import ch.systemsx.cisd.base.image.IImageTransformerFactory;
-import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
-import ch.systemsx.cisd.common.shared.basic.string.StringUtils;
-
 /**
- * Utility class to construct various kinds of image transformations.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformationBuffer}
+ * instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-public class ImageTransformationBuffer
+public class ImageTransformationBuffer extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformationBuffer
 {
-    private static final String PREDEFINED_TRANSFORMATIONS_CODE_PREFIX = "_";
-
-    private final List<ImageTransformation> imageTransformations;
-
-    public ImageTransformationBuffer()
-    {
-        this.imageTransformations = new ArrayList<ImageTransformation>();
-    }
-
-    /**
-     * Appends a single transformation and returns it. Note that code of each added transformation
-     * should be unique.
-     */
-    public ImageTransformation append(ImageTransformation transformation)
-    {
-        appendAll(transformation);
-        return transformation;
-    }
-
-    /**
-     * Appends any specified transformations. Note that code of each added transformation should be
-     * unique.
-     */
-    public void appendAll(ImageTransformation... transformations)
-    {
-        for (ImageTransformation transformation : transformations)
-        {
-            imageTransformations.add(transformation);
-        }
-        ensureTransformationCodesUnique();
-    }
-
-    // returns a set of used transformation codes
-    private Set<String> ensureTransformationCodesUnique()
-    {
-        Set<String> usedTransformationCodes = new HashSet<String>();
-        for (ImageTransformation transformation : imageTransformations)
-        {
-            String code = transformation.getCode();
-            if (usedTransformationCodes.contains(code))
-            {
-                throw new IllegalArgumentException("Two transformations have the same code: "
-                        + code);
-            }
-            usedTransformationCodes.add(code);
-        }
-        return usedTransformationCodes;
-    }
-
-    private void ensureOnlyOneDefault()
-    {
-        ImageTransformation defaultTansf = null;
-        for (ImageTransformation transformation : imageTransformations)
-        {
-            if (transformation.isDefault())
-            {
-                if (defaultTansf == null)
-                {
-                    defaultTansf = transformation;
-                } else
-                {
-                    throw ConfigurationFailureException.fromTemplate(
-                            "Only one image transformation can be default, but two were found: '%s' and "
-                                    + "'%s'.", defaultTansf.getLabel(), transformation.getLabel());
-                }
-            }
-        }
-    }
-
-    /** @returns all appended transformations */
-    public ImageTransformation[] getTransformations()
-    {
-        // codes of transformations could be changed after they have been added
-        ensureTransformationCodesUnique();
-        ensureOnlyOneDefault();
-        return imageTransformations.toArray(new ImageTransformation[imageTransformations.size()]);
-    }
-
-    // -------------- bit shifting transformations ---------------------
-
-    /**
-     * Appends transformations which extracts a range of grayscale image colors by choosing 8
-     * consecutive bits. All shifts which make sense for 12 bit images will be appended (from 0 to
-     * 4).
-     * 
-     * @return appended transformations. They can be used to e.g. modify their label or description.
-     */
-    public ImageTransformation[] appendAllBitShiftsFor12BitGrayscale()
-    {
-        return appendAllAvailableGrayscaleBitShifts(12);
-    }
-
-    /**
-     * Appends transformations which extracts a range of grayscale image colors by choosing 8
-     * consecutive bits. All shifts which make sense for 16 bit images will be appended (from 0 to
-     * 8).
-     * 
-     * @return appended transformations. They can be used to e.g. modify their label or description.
-     */
-    public ImageTransformation[] appendAllBitShiftsFor16BitGrayscale()
-    {
-        return appendAllAvailableGrayscaleBitShifts(16);
-    }
-
-    private ImageTransformation[] appendAllAvailableGrayscaleBitShifts(int totalNumberOfBits)
-    {
-        int transformationsNumber = totalNumberOfBits - 8 + 1;
-        ImageTransformation[] transformations = new ImageTransformation[transformationsNumber];
-        for (int i = 0; i < transformationsNumber; i++)
-        {
-            transformations[i] = appendGrayscaleBitShifting(i);
-        }
-        return transformations;
-    }
-
-    /**
-     * Appends transformation which extracts a range of grayscale image colors by choosing 8
-     * consecutive bits starting from the specified one.
-     * 
-     * @return appended transformation. It can be used to e.g. modify its label or description.
-     */
-    public ImageTransformation appendGrayscaleBitShifting(int shiftBits)
-    {
-        return append(createGrayscaleBitShifting(shiftBits));
-    }
-
-    /**
-     * Creates a transformation which extracts a range of grayscale image colors by choosing 8
-     * consecutive bits, staring from the specified one.
-     * <p>
-     * This method is useful when one wants to modify the default code, label or description
-     * afterwards.
-     */
-    private static ImageTransformation createGrayscaleBitShifting(int shiftBits)
-    {
-        if (shiftBits < 0)
-        {
-            throw new IllegalArgumentException(
-                    "Cannot create an image transformation which shifts by a negative number of bits");
-        }
-        String label = createBitShiftingTransformationLabel(shiftBits);
-        String code = createBitShiftingTransformationCode(shiftBits);
-        String description = createBitShiftingTransformationDescription(shiftBits);
-
-        IImageTransformerFactory factory = new BitShiftingImageTransformerFactory(shiftBits);
-        return new ImageTransformation(code, label, description, factory);
-    }
-
-    private static String createBitShiftingTransformationCode(int shiftBits)
-    {
-        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "BIT_SHIFTING_" + shiftBits;
-    }
-
-    private static String createBitShiftingTransformationDescription(int shiftBits)
-    {
-        return String.format(
-                "Shows a range of grayscale image colors by visualising only 8 consecutive bits from %d to %d. "
-                        + "Useful for extracting information from 12 and 16 bit images.",
-                shiftBits, shiftBits + 7);
-    }
-
-    private static String createBitShiftingTransformationLabel(int shiftBits)
-    {
-        return String.format("Show bits %d-%d", shiftBits, shiftBits + 7);
-    }
-
-    // -----------------------------
-
-    /**
-     * Appends transformation which converts grayscale image pixel intensities from the range
-     * [blackPointIntensity, whitePointIntensity] to 8 bit color depth. Useful to compare images of
-     * higher color depth with each other when they do not use the whole range of available
-     * intensities.
-     * 
-     * @return appended transformation. It can be used to e.g. modify its label or description.
-     */
-    public ImageTransformation appendRescaleGrayscaleIntensity(int blackPointIntensity,
-            int whitePointIntensity)
-    {
-        return appendRescaleGrayscaleIntensity(blackPointIntensity, whitePointIntensity, null);
-    }
-
-    /**
-     * See {@link #appendRescaleGrayscaleIntensity(int, int)}.
-     * <p>
-     * Additionally sets the label of the transformation.
-     * 
-     * @return appended transformation. It can be used to e.g. modify its label or description.
-     */
-    public ImageTransformation appendRescaleGrayscaleIntensity(int blackPointIntensity,
-            int whitePointIntensity, String userFriendlyLabelOrNull)
-    {
-        return append(createRescaleGrayscaleIntensity(blackPointIntensity, whitePointIntensity,
-                userFriendlyLabelOrNull));
-    }
-
-    /**
-     * Creates a transformation which converts grayscale image pixel intensities from the range
-     * [blackPointIntensity, whitePointIntensity] to 8 bit color depth.
-     * <p>
-     * This method is useful when one wants to modify the default code, label or description
-     * afterwards.
-     * 
-     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
-     *            assigned.
-     */
-    public static ImageTransformation createRescaleGrayscaleIntensity(int blackPointIntensity,
-            int whitePointIntensity, String userFriendlyLabelOrNull)
-    {
-        if (blackPointIntensity > whitePointIntensity || blackPointIntensity < 0
-                || whitePointIntensity < 0)
-        {
-            throw new IllegalArgumentException(String.format(
-                    "Cannot create an image transformation because the range "
-                            + "of intensities is invalid: [%d, %d]", blackPointIntensity,
-                    whitePointIntensity));
-        }
-        String label = createIntensityRangeTransformationLabel(userFriendlyLabelOrNull);
-        String code =
-                createIntensityRangeTransformationCode(blackPointIntensity, whitePointIntensity);
-        String description =
-                createIntensityRangeTransformationDescription(blackPointIntensity,
-                        whitePointIntensity);
-
-        IImageTransformerFactory factory =
-                new IntensityRangeImageTransformerFactory(blackPointIntensity, whitePointIntensity);
-        return new ImageTransformation(code, label, description, factory);
-    }
-
-    private static String createIntensityRangeTransformationCode(int blackPointIntensity,
-            int whitePointIntensity)
-    {
-        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "INTENSITY_LEVEL_" + blackPointIntensity
-                + "_" + whitePointIntensity;
-    }
-
-    private static String createIntensityRangeTransformationDescription(int blackPointIntensity,
-            int whitePointIntensity)
-    {
-        return String
-                .format("Transforms grayscale image by converting intensities of its pixels "
-                        + "which are in the range [%d, %d] to 8 bit color depth. "
-                        + "The range of intensities is usually calculated by processing a series of 12 or 16 bit images, "
-                        + "then the transformation becomes useful to compare these images with each other in 8 bit color depth, "
-                        + "especially when they use only a small part of available intensities range.",
-                        blackPointIntensity, whitePointIntensity);
-    }
-
-    private static String createIntensityRangeTransformationLabel(String labelOrNull)
-    {
-        return labelOrNull != null ? labelOrNull : "Fixed rescaling";
-    }
-
-    // --------------------------
-
-    /**
-     * Appends transformation which converts each single grayscale image to 8 bit color depth and
-     * rescales pixels intensities so that the darkest pixel will become black and the brightest
-     * will become white.
-     * <p>
-     * Note that by default openBIS applies this transformation with threshold 0 if it deals with
-     * grayscale image where color depth is bigger then 8 bit. So calling this method with parameter
-     * 0 is not necessary.
-     * </p>
-     * 
-     * @param threshold value form 0 to 1, it specifies the percentage of darkest and brightest
-     *            pixels which will be ignored (they will all become black or white).
-     * @return appended transformation. It can be used to e.g. modify its label or description.
-     */
-    public ImageTransformation appendAutoRescaleGrayscaleIntensity(float threshold)
-    {
-        return appendAutoRescaleGrayscaleIntensity(threshold, null);
-    }
-
-    /**
-     * See {@link #appendAutoRescaleGrayscaleIntensity(float)}.
-     * <p>
-     * Additionally sets the label of the transformation.
-     * 
-     * @return appended transformation. It can be used to e.g. modify its label or description.
-     */
-    public ImageTransformation appendAutoRescaleGrayscaleIntensity(float threshold,
-            String userFriendlyLabelOrNull)
-    {
-        return append(createAutoRescaleGrayscaleIntensity(threshold, userFriendlyLabelOrNull));
-    }
-
-    /**
-     * Creates a transformation which converts each single grayscale image to 8 bit color depth and
-     * rescales pixels intensities so that the darkest pixel will become black and the brightest
-     * will become white (with some threshold margin).
-     * <p>
-     * This method is useful when one wants to modify the default code, label or description
-     * afterwards.
-     * 
-     * @param threshold value form 0 to 1, it specifies the percentage of darkest and brightest
-     *            pixels which will be ignored (they will all become black or white).
-     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
-     *            assigned.
-     */
-    private static ImageTransformation createAutoRescaleGrayscaleIntensity(float threshold,
-            String userFriendlyLabelOrNull)
-    {
-        if (threshold < 0 || threshold > 1)
-        {
-            throw new IllegalArgumentException(
-                    "Invalid value of the threshold, should be between 0 and 1, but is: "
-                            + threshold);
-        }
-        String label =
-                createAutoRescaleIntensityTransformationLabel(userFriendlyLabelOrNull, threshold);
-        String code = createAutoRescaleIntensityTransformationCode(threshold);
-        String description = createAutoRescaleIntensityTransformationDescription(threshold);
-
-        IImageTransformerFactory factory =
-                new AutoRescaleIntensityImageTransformerFactory(threshold);
-        return new ImageTransformation(code, label, description, factory);
-    }
-
-    private static String createAutoRescaleIntensityTransformationCode(float threshold)
-    {
-        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "AUTO_INTENSITY_LEVEL_" + (threshold * 100);
-    }
-
-    private static String createAutoRescaleIntensityTransformationDescription(float threshold)
-    {
-        return String
-                .format("Creates a transformation which converts each single grayscale image to 8 bit color depth and "
-                        + "rescales pixels intensities so that the darkest pixel will become black and the brightest "
-                        + "will become white (threshold margin: %s).",
-                        new DecimalFormat("#.###").format(threshold));
-    }
-
-    @Private
-    static String createAutoRescaleIntensityTransformationLabel(String labelOrNull, float threshold)
-    {
-        String thresholdPercentage = new DecimalFormat("##.#").format(threshold * 100);
-        return labelOrNull != null ? labelOrNull : String.format("Optimal (image, %s%% cut)",
-                thresholdPercentage);
-    }
-
-    // --------------------------
-
-    /**
-     * Allows to transform the images with ImageMagic convert tool (which has to be installed and
-     * accessible). Convert will be called with the specified parameters.
-     * 
-     * @return appended transformation. It can be used to e.g. modify its label or description.
-     */
-    public ImageTransformation appendImageMagicConvert(String convertCliArguments)
-    {
-        return appendImageMagicConvert(convertCliArguments, null);
-    }
-
-    /**
-     * See {@link #appendImageMagicConvert(String)}.
-     * <p>
-     * Additionally sets the label of the transformation.
-     * 
-     * @return appended transformation. It can be used to e.g. modify its label or description.
-     */
-    public ImageTransformation appendImageMagicConvert(String convertCliArguments,
-            String userFriendlyLabelOrNull)
-    {
-        return append(createImageMagicConvert(convertCliArguments,
-                generateUniqueConvertTransformationCode(), userFriendlyLabelOrNull));
-    }
-
-    /**
-     * Creates a transformation which converts the images with ImageMagic convert tool.
-     * <p>
-     * This method is useful when one wants to modify the default code, label or description
-     * afterwards.
-     * 
-     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
-     *            assigned.
-     */
-    private static ImageTransformation createImageMagicConvert(String convertCliArguments,
-            String transformationCode, String userFriendlyLabelOrNull)
-    {
-        if (StringUtils.isBlank(convertCliArguments))
-        {
-            throw new IllegalArgumentException(
-                    "No argument has been specified for the 'convert' command");
-        }
-        if (StringUtils.isBlank(transformationCode))
-        {
-            throw new IllegalArgumentException("Transformation has not been specified");
-        }
-        String label =
-                createImageMagicConvertTransformationLabel(convertCliArguments,
-                        userFriendlyLabelOrNull);
-        String description = createImageMagicConvertTransformationDescription(convertCliArguments);
-
-        IImageTransformerFactory factory =
-                new ConvertToolImageTransformerFactory(convertCliArguments);
-        return new ImageTransformation(transformationCode, label, description, factory);
-    }
-
-    private static String createImageMagicConvertTransformationDescription(
-            String convertCliArguments)
-    {
-        return String.format("Transforms images with ImageMagic tool by calling: 'convert %s ...'",
-                convertCliArguments);
-    }
-
-    private static String createImageMagicConvertTransformationLabel(String convertCliArguments,
-            String labelOrNull)
-    {
-        return labelOrNull != null ? labelOrNull : String.format("Convert (%s)",
-                convertCliArguments);
-    }
-
-    private String generateUniqueConvertTransformationCode()
-    {
-        int i = 1;
-        Set<String> usedTransformationCodes = ensureTransformationCodesUnique();
-        while (usedTransformationCodes.contains(getConvertTransformationCode(i)))
-        {
-            i++;
-        }
-        return getConvertTransformationCode(i);
-    }
-
-    private static String getConvertTransformationCode(int seqNumber)
-    {
-        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "CONVERT_" + seqNumber;
-    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/IntensityRangeImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/IntensityRangeImageTransformerFactory.java
index 4c588dd0b97c041f007a3176fd14bdbce02677e3..41567f4d910252106a4df6990b59a2d0cafd8863 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/IntensityRangeImageTransformerFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/IntensityRangeImageTransformerFactory.java
@@ -16,67 +16,22 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
 
-import java.awt.image.BufferedImage;
-
-
-import ch.systemsx.cisd.base.image.IImageTransformer;
-import ch.systemsx.cisd.base.image.IImageTransformerFactory;
-
-import ch.systemsx.cisd.base.annotation.JsonObject;
-import ch.systemsx.cisd.common.image.IntensityRescaling;
-import ch.systemsx.cisd.common.image.IntensityRescaling.Levels;
-
 /**
- * Transformation performed by
- * {@link IntensityRescaling#rescaleIntensityLevelTo8Bits(BufferedImage, Levels)}.
- * <p>
- * Warning: The serialized version of this class can be stored in the database for each image.
- * Moving this class to a different package or changing it in a backward incompatible way would make
- * all the saved transformations invalid.
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.IntensityRangeImageTransformerFactory}
+ * instead
  * 
- * @author Tomasz Pylak
+ * @author Jakub Straszewski
  */
-@JsonObject("IntensityRangeImageTransformerFactory")
-public class IntensityRangeImageTransformerFactory implements IImageTransformerFactory
+public class IntensityRangeImageTransformerFactory
+        extends
+        ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.IntensityRangeImageTransformerFactory
 {
     private static final long serialVersionUID = 1L;
 
-    private final int blackPointIntensity;
-
-    private final int whitePointIntensity;
-
     public IntensityRangeImageTransformerFactory(int blackPointIntensity, int whitePointIntensity)
     {
-        this.blackPointIntensity = blackPointIntensity;
-        this.whitePointIntensity = whitePointIntensity;
-    }
-
-    public int getBlackPointIntensity()
-    {
-        return blackPointIntensity;
-    }
-
-    public int getWhitePointIntensity()
-    {
-        return whitePointIntensity;
-    }
-
-    @Override
-    public IImageTransformer createTransformer()
-    {
-        return new IImageTransformer()
-            {
-                @Override
-                public BufferedImage transform(BufferedImage image)
-                {
-                    if (IntensityRescaling.isNotGrayscale(image))
-                    {
-                        return image;
-                    }
-                    Levels levels = new Levels(blackPointIntensity, whitePointIntensity);
-                    return IntensityRescaling.rescaleIntensityLevelTo8Bits(image, levels);
-                }
-            };
+        super(blackPointIntensity, whitePointIntensity);
     }
 
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/utils/DropboxUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/utils/DropboxUtils.java
index 2a2c55d1325008401bd72ab907af9d604bcc26d8..6885a2a6b54a371d073a3f680adcef4d50317b9f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/utils/DropboxUtils.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/utils/DropboxUtils.java
@@ -16,48 +16,12 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.utils;
 
-import java.util.Collection;
-import java.util.Map;
-
-import ch.systemsx.cisd.common.geometry.SpatialPoint;
-import ch.systemsx.cisd.openbis.dss.etl.TileGeometryOracle;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Location;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.PlateUtils;
-
 /**
- * @author Tomasz Pylak
+ * This class is obsolete, and should not be used. Use
+ * {@link ch.systemsx.cisd.openbis.dss.etl.dto.api.utils.DropboxUtils} instead
+ * 
+ * @author Jakub Straszewski
  */
-public class DropboxUtils
+public class DropboxUtils extends ch.systemsx.cisd.openbis.dss.etl.dto.api.utils.DropboxUtils
 {
-    /**
-     * Translates a row number into letter code. Thus, 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB,
-     * etc.
-     */
-    public static String translateRowNumberIntoLetterCode(int rowNumber)
-    {
-        return PlateUtils.translateRowNumberIntoLetterCode(rowNumber);
-    }
-
-    /**
-     * Figures the tile geometry based on all locations present in the it.
-     */
-    public static Geometry figureGeometry(Collection<Location> tileLocations)
-    {
-        return TileGeometryOracle.figureGeometry(tileLocations);
-    }
-
-    /**
-     * Tries to figure out tile locations based on their spatial coordinates.
-     * <p>
-     * Two spatial points (x1, y1) and (x2, y2) are assumed lie in the same tile when abs(x1-x2) <
-     * epsilon and abs(y1-y2) < epsilon.
-     * 
-     * @param epsilon see the javadoc of the method
-     */
-    public static Map<Integer/* tile number */, Location> tryFigureLocations(
-            Map<Integer/* tile number */, SpatialPoint> tileToSpatialPointMap, double epsilon)
-    {
-        return TileGeometryOracle.tryFigureLocations(tileToSpatialPointMap, epsilon);
-    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/FeatureListDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/FeatureListDataConfig.java
index 24cefa209aea33c830e958fc40154aa32c2354ef..362eadb658235909f656e0266caf90e0e637b4f9 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/FeatureListDataConfig.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/FeatureListDataConfig.java
@@ -18,7 +18,7 @@ package ch.systemsx.cisd.openbis.dss.etl.dto.api.v2;
 
 import java.util.Collection;
 
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetUpdatable;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSetUpdatable;
 
 /**
  * The builder class for creation of feature lists.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IFeatureVectorDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IFeatureVectorDataSet.java
index d042b0639c7ec4ae3c41150a528313782f917c25..d6a72dca6c6f7f9e92d9169afdc85c2e69026471 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IFeatureVectorDataSet.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IFeatureVectorDataSet.java
@@ -16,11 +16,11 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v2;
 
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
 
 /**
  * Extension of {@link IDataSet} specific for feature vector data sets.
- *
+ * 
  * @author Franz-Josef Elmer
  */
 public interface IFeatureVectorDataSet extends IDataSet
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImageDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImageDataSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..6cbf0bacff479fa3eab189c3fad27f718e506f07
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImageDataSet.java
@@ -0,0 +1,60 @@
+/*
+ * 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.dss.etl.dto.api.v2;
+
+import java.util.List;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
+
+/**
+ * Container image dataset which contains original and thumbnail physical datasets.
+ * 
+ * @author Tomasz Pylak
+ */
+public interface IImageDataSet extends IDataSet
+{
+    IDataSet getOriginalDataset();
+
+    List<IDataSet> getThumbnailDatasets();
+
+    /** Sets analysis procedure. Makes sense only for segmentation datasets. */
+    void setAnalysisProcedure(String analysisProcedure);
+
+    /**
+     * If this method is called the contained data sets (original data set and thumbnails) will
+     * automatically linked to the sample specified by
+     * {@link IDataSet#setSample(ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISampleImmutable)}
+     * . By default there will be no such links.
+     * 
+     * @deprecated this method is for backwards compatibility only
+     */
+    @Deprecated
+    void establishSampleLinkForContainedDataSets();
+
+    /**
+     * Utility method to find out the plate geometry by looking for which wells images are
+     * available.
+     * 
+     * @return a constant which can be used as a vocabulary term value for $PLATE_GEOMETRY property
+     *         of a plate/
+     * @throws UserFailureException if all available geometries in openBIS are too small (there is a
+     *             well outside).
+     */
+    String figureGeometry();
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImagingDataSetRegistrationTransactionV2.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImagingDataSetRegistrationTransactionV2.java
index ca39a0e38935bf6b35b3f6c5e6465f6bbadb01da..65686d7eaf89a4c19812e26a81798f88c06855ba 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImagingDataSetRegistrationTransactionV2.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImagingDataSetRegistrationTransactionV2.java
@@ -18,11 +18,10 @@ package ch.systemsx.cisd.openbis.dss.etl.dto.api.v2;
 
 import java.io.File;
 
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
 import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSetRegistrationTransactionV2;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeaturesBuilder;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IImageDataSet;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
 
 /**
  * Extension of {@link IDataSetRegistrationTransactionV2} for screening.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImagingDatasetFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImagingDatasetFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..8053996a4c7aceb7801a1347ee000bee39efbe93
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/IImagingDatasetFactory.java
@@ -0,0 +1,111 @@
+/*
+ * 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.dss.etl.dto.api.v2;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.v2.DataSetRegistrationService;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeaturesBuilder;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
+
+/**
+ * Factory for defining image and feature vector datasets.
+ * 
+ * @author Tomasz Pylak
+ */
+public interface IImagingDatasetFactory
+{
+    /**
+     * Creates image dataset details. Used if <br>
+     * 1. more then one dataset is created in one transaction and using
+     * {@link #registerImageDataset} is not sufficient or <br>
+     * 2. {@link SimpleImageDataConfig} is not sufficient to describe the dataset and further
+     * modifications on the dataset detail object are required.
+     */
+    @Deprecated
+    DataSetRegistrationDetails<ImageDataSetInformation> createImageRegistrationDetails(
+            SimpleImageDataConfig imageDataSet, File incomingDatasetFolder);
+
+    /**
+     * A convenience method to register the specified image dataset in a separate transaction.
+     * 
+     * @param imageDataSet simple dataset specification
+     */
+    boolean registerImageDataset(SimpleImageDataConfig imageDataSet, File incomingDatasetFolder,
+            DataSetRegistrationService<ImageDataSetInformation> service);
+
+    /**
+     * A convenience method to register the specified image dataset in a separate transaction.
+     * 
+     * @param imageDatasetDetails advanced dataset specification
+     */
+    @Deprecated
+    boolean registerImageDataset(
+            DataSetRegistrationDetails<ImageDataSetInformation> imageDatasetDetails,
+            File incomingDatasetFolder, DataSetRegistrationService<ImageDataSetInformation> service);
+
+    /**
+     * Allows to define feature vectors of one image analysis dataset. Used to define a dataset
+     * details with {@link #createFeatureVectorDatasetDetails(IFeaturesBuilder)}.
+     */
+    IFeaturesBuilder createFeaturesBuilder();
+
+    /**
+     * Creates feature vector dataset details by using the specified builder.
+     */
+    DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorDatasetDetails(
+            IFeaturesBuilder featureBuilder);
+
+    /**
+     * Creates feature vector dataset details by parsing the specified CSV file.
+     * <p>
+     * CSV format can be configured with following properties:
+     * 
+     * <pre>
+     *   # Separator character between headers and row cells.
+     *   separator = ,
+     *   ignore-comments = true
+     *   # Header of the column denoting the row of a well.
+     *   well-name-row = row
+     *   # Header of the column denoting the column of a well.
+     *   well-name-col = col
+     *   well-name-col-is-alphanum = true
+     * </pre>
+     * 
+     * @throws IOException if file cannot be parsed
+     */
+    DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorDatasetDetails(
+            String csvFilePath, Properties properties) throws IOException;
+
+    /**
+     * Utility method to find out the plate geometry by looking for which wells images are
+     * available.
+     * 
+     * @return a constant which can be used as a vocabulary term value for $PLATE_GEOMETRY property
+     *         of a plate/
+     * @throws UserFailureException if all available geometries in openBIS are too small (there is a
+     *             well outside).
+     */
+    String figureGeometry(DataSetRegistrationDetails<ImageDataSetInformation> registrationDetails);
+
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/SimpleFeatureVectorDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/SimpleFeatureVectorDataConfig.java
index 548c2765c753d76014d22e23e40d33a5835a8b6d..4389e9fca7cb52c0dfa9a9dfc5b8524de42b3a46 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/SimpleFeatureVectorDataConfig.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/SimpleFeatureVectorDataConfig.java
@@ -18,8 +18,8 @@ package ch.systemsx.cisd.openbis.dss.etl.dto.api.v2;
 
 import java.util.Properties;
 
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeaturesBuilder;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeaturesBuilder;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeaturesBuilder;
 
 /**
  * Configuration for creating a feature vector data set.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/FeatureVectorContainerDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/FeatureVectorContainerDataSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..3047aa608fef028eb0ed5b30a40cfa5665b83cfa
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/FeatureVectorContainerDataSet.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2012 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.etl.dto.api.v2.impl;
+
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.ANALYSIS_PROCEDURE;
+
+import java.io.File;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IFeatureVectorDataSet;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IExperimentImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISampleImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
+
+/**
+ * @author jakubs
+ */
+public class FeatureVectorContainerDataSet extends DataSet<DataSetInformation> implements
+        IFeatureVectorDataSet
+{
+
+    /**
+     * @param registrationDetails
+     * @param dataSetFolder
+     * @param service
+     */
+    public FeatureVectorContainerDataSet(
+            DataSetRegistrationDetails<? extends DataSetInformation> registrationDetails,
+            File dataSetFolder, IEncapsulatedOpenBISService service)
+    {
+        super(registrationDetails, dataSetFolder, service);
+    }
+
+    private FeatureVectorDataSet originalDataset;
+
+    public IDataSet getOriginalDataset()
+    {
+        return originalDataset;
+    }
+
+    public void setOriginalDataSet(FeatureVectorDataSet mainDataSet)
+    {
+        this.originalDataset = mainDataSet;
+    }
+
+    @Override
+    public void setAnalysisProcedure(String analysisProcedure)
+    {
+        getRegistrationDetails().getDataSetInformation().getDataSetProperties()
+                .add(new NewProperty(ANALYSIS_PROCEDURE, analysisProcedure));
+    }
+
+    @Override
+    public void setSample(ISampleImmutable sampleOrNull)
+    {
+        super.setSample(sampleOrNull);
+        if (originalDataset != null)
+        {
+            originalDataset.setSample(sampleOrNull);
+            // calling this line assures, that the sample in the contained dataset will not be kept.
+            originalDataset.getRegistrationDetails().getDataSetInformation().setLinkSample(false);
+        }
+    }
+
+    @Override
+    public void setExperiment(IExperimentImmutable experimentOrNull)
+    {
+        super.setExperiment(experimentOrNull);
+        if (originalDataset != null)
+        {
+            originalDataset.setExperiment(experimentOrNull);
+        }
+    }
+
+    @Override
+    public void setPropertyValue(String propertyCode, String propertyValue)
+    {
+        getRegistrationDetails().setPropertyValue(propertyCode, propertyValue);
+    }
+
+    @Override
+    public File getDataSetStagingFolder()
+    {
+        return originalDataset.getDataSetStagingFolder();
+    }
+
+    public static String getContainerAnalysisType(String dataSetTypeCode)
+    {
+        if (!isHCSAnalysisDataSetType(dataSetTypeCode))
+        {
+            throw UserFailureException
+                    .fromTemplate(
+                            "Feature vector data set type should conform to the HCS_ANALYSIS_* pattern, but was %s",
+                            dataSetTypeCode);
+
+        }
+
+        String containerDatasetTypeCode =
+                ScreeningConstants.HCS_ANALYSIS_PREFIX
+                        + ScreeningConstants.IMAGE_CONTAINER_DATASET_TYPE_MARKER
+                        + dataSetTypeCode
+                                .substring(ScreeningConstants.HCS_ANALYSIS_PREFIX.length());
+
+        return containerDatasetTypeCode;
+    }
+
+    private static boolean isHCSAnalysisDataSetType(String mainDatasetTypeCode)
+    {
+        String prefix = ScreeningConstants.HCS_ANALYSIS_PREFIX;
+        if (mainDatasetTypeCode.startsWith(prefix))
+        {
+            if (mainDatasetTypeCode
+                    .contains(ScreeningConstants.IMAGE_CONTAINER_DATASET_TYPE_MARKER))
+            {
+                throw UserFailureException
+                        .fromTemplate(
+                                "The specified analysis dataset type '%s' should not be of container type, but contains '%s' in the type code.",
+                                mainDatasetTypeCode,
+                                ScreeningConstants.IMAGE_CONTAINER_DATASET_TYPE_MARKER);
+            }
+            return true;
+        } else
+        {
+            return false;
+        }
+    }
+
+    @Override
+    public void setDataSetType(String dataSetTypeCode)
+    {
+        originalDataset.setDataSetType(dataSetTypeCode);
+
+        super.setDataSetType(getContainerAnalysisType(dataSetTypeCode));
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/FeatureVectorDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/FeatureVectorDataSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..25d2ccaa59754f8eac1a0361d9c7257cd1098375
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/FeatureVectorDataSet.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2012 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.etl.dto.api.v2.impl;
+
+import java.io.File;
+import java.util.List;
+
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IFeatureVectorDataSet;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IDataSetImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IExperimentImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IExternalDataManagementSystemImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISampleImmutable;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSetType;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class FeatureVectorDataSet extends DataSet<FeatureVectorDataSetInformation> implements
+        IFeatureVectorDataSet
+{
+    private final DataSet<FeatureVectorDataSetInformation> dataSet;
+
+    public FeatureVectorDataSet(DataSet<FeatureVectorDataSetInformation> dataSet,
+            IEncapsulatedOpenBISService service)
+    {
+        super(dataSet.getRegistrationDetails(), dataSet.getDataSetStagingFolder(), service);
+        this.dataSet = dataSet;
+    }
+
+    @Override
+    public void setAnalysisProcedure(String analysisProcedure)
+    {
+        dataSet.getRegistrationDetails().getDataSetInformation()
+                .setAnalysisProcedure(analysisProcedure);
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return dataSet.equals(obj);
+    }
+
+    @Override
+    public DataSetRegistrationDetails<? extends FeatureVectorDataSetInformation> getRegistrationDetails()
+    {
+        return dataSet.getRegistrationDetails();
+    }
+
+    @Override
+    public File getDataSetStagingFolder()
+    {
+        return dataSet.getDataSetStagingFolder();
+    }
+
+    @Override
+    public String getDataSetCode()
+    {
+        return dataSet.getDataSetCode();
+    }
+
+    @Override
+    public IExperimentImmutable getExperiment()
+    {
+        return dataSet.getExperiment();
+    }
+
+    @Override
+    public ISampleImmutable getSample()
+    {
+        return dataSet.getSample();
+    }
+
+    @Override
+    public String getFileFormatType()
+    {
+        return dataSet.getFileFormatType();
+    }
+
+    @Override
+    public int getSpeedHint()
+    {
+        return dataSet.getSpeedHint();
+    }
+
+    @Override
+    public String getDataSetType()
+    {
+        return dataSet.getDataSetType();
+    }
+
+    @Override
+    public DataSetType getDataSetTypeWithPropertyTypes()
+    {
+        return dataSet.getDataSetTypeWithPropertyTypes();
+    }
+
+    @Override
+    public String getPropertyValue(String propertyCode)
+    {
+        return dataSet.getPropertyValue(propertyCode);
+    }
+
+    @Override
+    public List<String> getAllPropertyCodes()
+    {
+        return dataSet.getAllPropertyCodes();
+    }
+
+    @Override
+    public List<String> getParentDatasets()
+    {
+        return dataSet.getParentDatasets();
+    }
+
+    @Override
+    public List<String> getContainedDataSetCodes()
+    {
+        return dataSet.getContainedDataSetCodes();
+    }
+
+    @Override
+    public List<IDataSetImmutable> getChildrenDataSets()
+    {
+        return dataSet.getChildrenDataSets();
+    }
+
+    @Override
+    public String getContainerDataSet()
+    {
+        return dataSet.getContainerDataSet();
+    }
+
+    @Override
+    public IExternalDataManagementSystemImmutable getExternalDataManagementSystem()
+    {
+        return dataSet.getExternalDataManagementSystem();
+    }
+
+    @Override
+    public String getExternalCode()
+    {
+        return dataSet.getExternalCode();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return dataSet.hashCode();
+    }
+
+    @Override
+    public void setExperiment(IExperimentImmutable experiment)
+    {
+        dataSet.setExperiment(experiment);
+    }
+
+    @Override
+    public void setSample(ISampleImmutable sampleOrNull)
+    {
+        dataSet.setSample(sampleOrNull);
+    }
+
+    @Override
+    public void setFileFormatType(String fileFormatTypeCode)
+    {
+        dataSet.setFileFormatType(fileFormatTypeCode);
+    }
+
+    @Override
+    public boolean isMeasuredData()
+    {
+        return dataSet.isMeasuredData();
+    }
+
+    @Override
+    public void setMeasuredData(boolean measuredData)
+    {
+        dataSet.setMeasuredData(measuredData);
+    }
+
+    @Override
+    public void setSpeedHint(int speedHint)
+    {
+        dataSet.setSpeedHint(speedHint);
+    }
+
+    @Override
+    public void setDataSetType(String dataSetTypeCode)
+    {
+        dataSet.setDataSetType(dataSetTypeCode);
+    }
+
+    @Override
+    public void setPropertyValue(String propertyCode, String propertyValue)
+    {
+        dataSet.setPropertyValue(propertyCode, propertyValue);
+    }
+
+    @Override
+    public void setParentDatasets(List<String> parentDatasetCodes)
+    {
+        dataSet.setParentDatasets(parentDatasetCodes);
+    }
+
+    @Override
+    public boolean isContainerDataSet()
+    {
+        return dataSet.isContainerDataSet();
+    }
+
+    @Override
+    public void setContainedDataSetCodes(List<String> containedDataSetCodes)
+    {
+        dataSet.setContainedDataSetCodes(containedDataSetCodes);
+    }
+
+    @Override
+    public boolean isContainedDataSet()
+    {
+        return dataSet.isContainedDataSet();
+    }
+
+    @Override
+    public void setExternalDataManagementSystem(
+            IExternalDataManagementSystemImmutable externalDataManagementSystem)
+    {
+        dataSet.setExternalDataManagementSystem(externalDataManagementSystem);
+    }
+
+    @Override
+    public boolean isLinkDataSet()
+    {
+        return dataSet.isLinkDataSet();
+    }
+
+    @Override
+    public void setExternalCode(String externalCode)
+    {
+        dataSet.setExternalCode(externalCode);
+    }
+
+    @Override
+    public boolean isNoFileDataSet()
+    {
+        return dataSet.isNoFileDataSet();
+    }
+
+    @Override
+    public String toString()
+    {
+        return dataSet.toString();
+    }
+
+    @Override
+    public File tryDataSetContents()
+    {
+        return dataSet.tryDataSetContents();
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/ImageContainerDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/ImageContainerDataSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..640b56105908a5da1932250802a5b4742f0f1b17
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v2/impl/ImageContainerDataSet.java
@@ -0,0 +1,141 @@
+/*
+ * 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.dss.etl.dto.api.v2.impl;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSet;
+import ch.systemsx.cisd.openbis.dss.etl.PlateGeometryOracle;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IImageDataSet;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IExperimentImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISampleImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
+
+/**
+ * Represents an image data set for the registration API.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ImageContainerDataSet extends DataSet<DataSetInformation> implements IImageDataSet
+{
+    private DataSet<ImageDataSetInformation> originalDataset;
+
+    private List<IDataSet> thumbnailDatasets = Collections.emptyList();
+
+    private boolean establishSampleLinkForContainedDataSets = false;
+
+    public ImageContainerDataSet(
+            DataSetRegistrationDetails<? extends DataSetInformation> registrationDetails,
+            File dataSetFolder, IEncapsulatedOpenBISService service)
+    {
+        super(registrationDetails, dataSetFolder, service);
+    }
+
+    @Override
+    public void setAnalysisProcedure(String analysisProcedure)
+    {
+        setPropertyValue(ScreeningConstants.ANALYSIS_PROCEDURE, analysisProcedure);
+    }
+
+    @Override
+    public void establishSampleLinkForContainedDataSets()
+    {
+        establishSampleLinkForContainedDataSets = true;
+    }
+
+    public boolean sampleLinkForContainedDataSetsShouldBeEstablished()
+    {
+        return establishSampleLinkForContainedDataSets;
+    }
+
+    @Override
+    public DataSet<ImageDataSetInformation> getOriginalDataset()
+    {
+        return originalDataset;
+    }
+
+    public void setOriginalDataset(DataSet<ImageDataSetInformation> originalDataset)
+    {
+        this.originalDataset = originalDataset;
+    }
+
+    @Override
+    public List<IDataSet> getThumbnailDatasets()
+    {
+        return thumbnailDatasets;
+    }
+
+    public void setThumbnailDatasets(List<IDataSet> thumbnailDatasets)
+    {
+        this.thumbnailDatasets = thumbnailDatasets;
+    }
+
+    @Override
+    public void setSample(ISampleImmutable sampleOrNull)
+    {
+        super.setSample(sampleOrNull);
+        if (originalDataset != null)
+        {
+            originalDataset.setSample(sampleOrNull);
+            originalDataset.getRegistrationDetails().getDataSetInformation()
+                    .setLinkSample(establishSampleLinkForContainedDataSets);
+        }
+        for (IDataSet thumbnailDataset : thumbnailDatasets)
+        {
+            thumbnailDataset.setSample(sampleOrNull);
+            if (thumbnailDataset instanceof DataSet)
+            {
+                ((DataSet<?>) thumbnailDataset).getRegistrationDetails().getDataSetInformation()
+                        .setLinkSample(establishSampleLinkForContainedDataSets);
+            }
+        }
+    }
+
+    @Override
+    public void setExperiment(IExperimentImmutable experimentOrNull)
+    {
+        super.setExperiment(experimentOrNull);
+        if (originalDataset != null)
+        {
+            originalDataset.setExperiment(experimentOrNull);
+        }
+        for (IDataSet thumbnailDataset : thumbnailDatasets)
+        {
+            thumbnailDataset.setExperiment(experimentOrNull);
+        }
+    }
+
+    @Override
+    public String figureGeometry()
+    {
+        return PlateGeometryOracle.figureGeometry(getImageRegistrationDetails(), service);
+    }
+
+    @SuppressWarnings("unchecked")
+    private DataSetRegistrationDetails<ImageDataSetInformation> getImageRegistrationDetails()
+    {
+        return (DataSetRegistrationDetails<ImageDataSetInformation>) originalDataset
+                .getRegistrationDetails();
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/HCSImageFileExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/HCSImageFileExtractor.java
index 652ca1e0ee7db4112fd202f6c73098a6861bbc0f..0d48ced8df4d9eea846a73e2e37ffc7cdf558c2a 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/HCSImageFileExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/HCSImageFileExtractor.java
@@ -31,7 +31,7 @@ import org.apache.commons.lang.StringUtils;
 import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.openbis.dss.etl.AbstractImageFileExtractor;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dynamix.WellLocationMappingUtils.DynamixWellPosition;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/FeatureVectorContainerDataSetRegistrationFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/FeatureVectorContainerDataSetRegistrationFactory.java
similarity index 93%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/FeatureVectorContainerDataSetRegistrationFactory.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/FeatureVectorContainerDataSetRegistrationFactory.java
index f4a239ea7372d57ff3581db2fe0e251841920f15..579cab4043f326eddde309f452474751f31deb5e 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/FeatureVectorContainerDataSetRegistrationFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/FeatureVectorContainerDataSetRegistrationFactory.java
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import java.io.File;
 
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.v1.AbstractDataSetRegistrationDetailsFactory;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorContainerDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl.FeatureVectorContainerDataSet;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/ImagingDataSetRegistrationTransaction.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/ImagingDataSetRegistrationTransaction.java
similarity index 97%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/ImagingDataSetRegistrationTransaction.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/ImagingDataSetRegistrationTransaction.java
index 9a2faaae1ba2eda45711b332ddef41223a385833..4f42ec225f200da84a2b8f7ca23315737785eb69 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/ImagingDataSetRegistrationTransaction.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/ImagingDataSetRegistrationTransaction.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_CONTAINER_TYPE_SUBSTRING;
 import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_IMAGE_TYPE_SUBSTRING;
@@ -32,36 +32,35 @@ import java.util.Properties;
 
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
-import ch.systemsx.cisd.openbis.common.io.FileBasedContentNode;
-import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetUpdatable;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSet;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSetRegistrationTransaction;
-import ch.systemsx.cisd.etlserver.registrator.recovery.AutoRecoverySettings;
 import ch.systemsx.cisd.etlserver.registrator.v1.DataSetRegistrationService;
 import ch.systemsx.cisd.etlserver.registrator.v1.IDataSetRegistrationDetailsFactory;
+import ch.systemsx.cisd.openbis.common.io.FileBasedContentNode;
+import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent;
 import ch.systemsx.cisd.openbis.dss.Constants;
 import ch.systemsx.cisd.openbis.dss.etl.Hdf5ThumbnailGenerator;
 import ch.systemsx.cisd.openbis.dss.etl.Utils;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureDefinition;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorContainerDataSet;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSet;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeaturesBuilder;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageContainerDataSet;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailsInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.FeatureListDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IImageDataSet;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IImagingDataSetRegistrationTransaction;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.FeatureListDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.SimpleFeatureVectorDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleFeatureVectorDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl.FeatureVectorContainerDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl.FeatureVectorDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl.ImageContainerDataSet;
 import ch.systemsx.cisd.openbis.dss.etl.featurevector.CsvFeatureVectorParser;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IDataSetImmutable;
@@ -73,12 +72,6 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchCl
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchSubCriteria;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
 
-/**
- * 
- *
- * @author jakubs
- */
-
 /**
  * Imaging-specific transaction. Handles image datasets in a special way, other datasets are
  * registered using a standard procedure.
@@ -104,10 +97,10 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
             File workingDirectory, File stagingDirectory,
             DataSetRegistrationService<DataSetInformation> registrationService,
             IDataSetRegistrationDetailsFactory<DataSetInformation> registrationDetailsFactory,
-            String originalDirName, AutoRecoverySettings autoRecoverySettings)
+            String originalDirName)
     {
         super(rollBackStackParentFolder, workingDirectory, stagingDirectory, registrationService,
-                registrationDetailsFactory, autoRecoverySettings);
+                registrationDetailsFactory);
 
         assert registrationDetailsFactory instanceof JythonPlateDatasetFactory : "JythonPlateDatasetFactory expected, but got: "
                 + registrationDetailsFactory.getClass().getCanonicalName();
@@ -207,8 +200,8 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
                     "Setting of container dataset for feature list data set is obligatory");
         }
 
-        if (false == container.getDataSetType()
-                .startsWith(ScreeningConstants.HCS_ANALYSIS_ANY_CONTAINER_DATASET_TYPE_PREFIX))
+        if (false == container.getDataSetType().startsWith(
+                ScreeningConstants.HCS_ANALYSIS_ANY_CONTAINER_DATASET_TYPE_PREFIX))
         {
             throw new UserFailureException(
                     "Container for feature list must be of HCS_ANALYSIS_CONTAINER.* type");
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonImageContainerDataSetRegistrationFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonImageContainerDataSetRegistrationFactory.java
similarity index 93%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonImageContainerDataSetRegistrationFactory.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonImageContainerDataSetRegistrationFactory.java
index 47b0a25953158f7b41f11cc36845cd2c054abb08..843ce453207c48b97bdcaa517c499f48a4a2d6c7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonImageContainerDataSetRegistrationFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonImageContainerDataSetRegistrationFactory.java
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import java.io.File;
 
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.v1.AbstractDataSetRegistrationDetailsFactory;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageContainerDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl.ImageContainerDataSet;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonImageDataSetRegistrationFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonImageDataSetRegistrationFactory.java
similarity index 96%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonImageDataSetRegistrationFactory.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonImageDataSetRegistrationFactory.java
index 5054968787ea0c8a2e0da289b74610b65cfe3ddd..6c688efa466f82498f1ccce89f7e0aa70ef9e38b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonImageDataSetRegistrationFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonImageDataSetRegistrationFactory.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import ch.systemsx.cisd.etlserver.registrator.v1.AbstractDataSetRegistrationDetailsFactory;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDataSetHandler.java
similarity index 93%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDataSetHandler.java
index 66f033aa6a7da72eeec680864507b3b0d1bbe5b6..c0a8573482a60995ff58d302c9b2e8e895a03057 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDataSetHandler.java
@@ -1,4 +1,4 @@
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import java.io.File;
 
@@ -8,7 +8,6 @@ import ch.systemsx.cisd.etlserver.ITopLevelDataSetRegistratorDelegate;
 import ch.systemsx.cisd.etlserver.TopLevelDataSetRegistratorGlobalState;
 import ch.systemsx.cisd.etlserver.registrator.DataSetFile;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSetRegistrationTransaction;
-import ch.systemsx.cisd.etlserver.registrator.recovery.AutoRecoverySettings;
 import ch.systemsx.cisd.etlserver.registrator.v1.DataSetRegistrationService;
 import ch.systemsx.cisd.etlserver.registrator.v1.IDataSetRegistrationDetailsFactory;
 import ch.systemsx.cisd.etlserver.registrator.v1.JythonTopLevelDataSetHandler;
@@ -62,7 +61,7 @@ public class JythonPlateDataSetHandler extends JythonTopLevelDataSetHandler<Data
                 {
                     return new ImagingDataSetRegistrationTransaction(rollBackStackParentFolder,
                             workingDirectory, stagingDirectory, this, registrationDetailsFactory,
-                            originalDirName, AutoRecoverySettings.DO_NOT_USE_AUTO_RECOVERY);
+                            originalDirName);
                 }
             };
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandlerUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDataSetHandlerUtils.java
similarity index 96%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandlerUtils.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDataSetHandlerUtils.java
index 627f002be3b4e1bcb0896380d7880654633d6762..764153a9f02251af48ec8b54fcc4b3b6c5a240bc 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandlerUtils.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDataSetHandlerUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import java.util.Properties;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDatasetFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDatasetFactory.java
similarity index 98%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDatasetFactory.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDatasetFactory.java
index 44ec309f1c9052c4421b9d7dcfa7f9a76a0e3e2d..ba0c549122fbe50e6421f12956d4649d76f79ea9 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDatasetFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/JythonPlateDatasetFactory.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import java.io.File;
 import java.io.IOException;
@@ -30,13 +30,13 @@ import ch.systemsx.cisd.etlserver.registrator.v1.IDataSetRegistrationDetailsFact
 import ch.systemsx.cisd.etlserver.registrator.v1.AbstractOmniscientTopLevelDataSetRegistrator.OmniscientTopLevelDataSetRegistratorState;
 import ch.systemsx.cisd.etlserver.registrator.v1.JythonTopLevelDataSetHandler.ProgrammableDropboxObjectFactory;
 import ch.systemsx.cisd.openbis.dss.etl.PlateGeometryOracle;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeaturesBuilder;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureDefinition;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeaturesBuilder;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeaturesBuilder;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IImagingDatasetFactory;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.featurevector.CsvFeatureVectorParser;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/SimpleImageDataSetRegistrator.java
similarity index 96%
rename from screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java
rename to screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/SimpleImageDataSetRegistrator.java
index 185f28781de8620459747784f51d036fbdcb2fbb..766a48c7533e8a5208bf90c8cae748779d673735 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/SimpleImageDataSetRegistrator.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import java.awt.image.BufferedImage;
 import java.io.File;
@@ -48,20 +48,20 @@ import ch.systemsx.cisd.imagereaders.IImageReader;
 import ch.systemsx.cisd.imagereaders.ImageID;
 import ch.systemsx.cisd.imagereaders.ImageReaderFactory;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageIdentifier;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageMetadata;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IntensityRange;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Location;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleOverviewImageDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageIdentifier;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageMetadata;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IntensityRange;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Location;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleOverviewImageDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformation;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformationBuffer;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformationBuffer;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
 import ch.systemsx.cisd.openbis.dss.shared.DssScreeningUtils;
@@ -449,9 +449,9 @@ public class SimpleImageDataSetRegistrator
 
     private List<Channel> findChannelsToComputeFixedCommonIntensityRange(List<Channel> channels)
     {
-        final Map<String, ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IntensityRange> map =
+        final Map<String, ch.systemsx.cisd.openbis.dss.etl.dto.api.IntensityRange> map =
                 simpleImageConfig.getFixedIntensityRangeForAllImages();
-        final ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IntensityRange defaultLevelOrNull =
+        final ch.systemsx.cisd.openbis.dss.etl.dto.api.IntensityRange defaultLevelOrNull =
                 map.get(null);
         if (defaultLevelOrNull != null)
         {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/FeatureVectorContainerDataSetRegistrationFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/FeatureVectorContainerDataSetRegistrationFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..a70321d7e37bccbdff157e84c6b9603a69a99fa2
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/FeatureVectorContainerDataSetRegistrationFactory.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 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.etl.jython.v2;
+
+import java.io.File;
+
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.v2.AbstractDataSetRegistrationDetailsFactory;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.impl.FeatureVectorContainerDataSet;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+
+/**
+ * Factory class that creates FeatureVectorContainerDataSet
+ * 
+ * @author jakubs
+ */
+public class FeatureVectorContainerDataSetRegistrationFactory extends
+        AbstractDataSetRegistrationDetailsFactory<DataSetInformation>
+{
+
+    public FeatureVectorContainerDataSetRegistrationFactory(
+            ch.systemsx.cisd.etlserver.registrator.v2.AbstractOmniscientTopLevelDataSetRegistrator.OmniscientTopLevelDataSetRegistratorState registratorState,
+            DataSetInformation userProvidedDataSetInformationOrNull)
+    {
+        super(registratorState, userProvidedDataSetInformationOrNull);
+    }
+
+    @Override
+    public FeatureVectorContainerDataSet createDataSet(
+            DataSetRegistrationDetails<DataSetInformation> registrationDetails, File stagingFile)
+    {
+        IEncapsulatedOpenBISService service = registratorState.getGlobalState().getOpenBisService();
+        return new FeatureVectorContainerDataSet(registrationDetails, stagingFile, service);
+    }
+
+    @Override
+    protected DataSetInformation createDataSetInformation()
+    {
+        return new DataSetInformation();
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3032202f8e9ebaf20660d22193bd012953a2527
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java
@@ -0,0 +1,799 @@
+/*
+ * Copyright 2012 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.etl.jython.v2;
+
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_CONTAINER_TYPE_SUBSTRING;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_IMAGE_TYPE_SUBSTRING;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSetUpdatable;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSetRegistrationTransaction;
+import ch.systemsx.cisd.etlserver.registrator.v2.DataSetRegistrationService;
+import ch.systemsx.cisd.etlserver.registrator.v2.IDataSetRegistrationDetailsFactory;
+import ch.systemsx.cisd.openbis.common.io.FileBasedContentNode;
+import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent;
+import ch.systemsx.cisd.openbis.dss.Constants;
+import ch.systemsx.cisd.openbis.dss.etl.Hdf5ThumbnailGenerator;
+import ch.systemsx.cisd.openbis.dss.etl.Utils;
+import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureDefinition;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeaturesBuilder;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailsInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.FeatureListDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IImageDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.SimpleFeatureVectorDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.impl.FeatureVectorContainerDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.impl.FeatureVectorDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.impl.ImageContainerDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.featurevector.CsvFeatureVectorParser;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IDataSetImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchClause;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchClauseAttribute;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchSubCriteria;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
+
+/**
+ * Imaging-specific transaction. Handles image datasets in a special way, other datasets are
+ * registered using a standard procedure.
+ * <p>
+ * Note that this transaction is not parametrized by a concrete {@link DataSetInformation} subclass.
+ * It has to deal with {@link ImageDataSetInformation}, {@link FeatureVectorDataSetInformation} and
+ * {@link DataSetInformation} at the same time.
+ */
+@SuppressWarnings("rawtypes")
+public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTransaction
+{
+    private final IDataSetRegistrationDetailsFactory<ImageDataSetInformation> imageDatasetFactory;
+
+    private final IDataSetRegistrationDetailsFactory<DataSetInformation> imageContainerDatasetFactory;
+
+    private final String originalDirName;
+
+    private final JythonPlateDatasetFactory factory;
+
+    @SuppressWarnings("unchecked")
+    public ImagingDataSetRegistrationTransaction(File rollBackStackParentFolder,
+            File workingDirectory, File stagingDirectory,
+            DataSetRegistrationService<DataSetInformation> registrationService,
+            IDataSetRegistrationDetailsFactory<DataSetInformation> registrationDetailsFactory,
+            String originalDirName)
+    {
+        super(rollBackStackParentFolder, workingDirectory, stagingDirectory, registrationService,
+                registrationDetailsFactory);
+
+        assert registrationDetailsFactory instanceof JythonPlateDatasetFactory : "JythonPlateDatasetFactory expected, but got: "
+                + registrationDetailsFactory.getClass().getCanonicalName();
+
+        factory = (JythonPlateDatasetFactory) registrationDetailsFactory;
+        this.imageDatasetFactory = factory.imageDatasetFactory;
+        this.imageContainerDatasetFactory = factory.imageContainerDatasetFactory;
+        this.originalDirName = originalDirName;
+    }
+
+    public JythonPlateDatasetFactory getFactory()
+    {
+        return factory;
+    }
+
+    public IImageDataSet createNewImageDataSet(SimpleImageDataConfig imageDataSet,
+            File incomingFolderWithImages)
+    {
+        DataSetRegistrationDetails<ImageDataSetInformation> details =
+                SimpleImageDataSetRegistrator.createImageDatasetDetails(imageDataSet,
+                        incomingFolderWithImages, imageDatasetFactory);
+        return createNewImageDataSet(details);
+    }
+
+    public IDataSet createNewOverviewImageDataSet(SimpleImageDataConfig imageDataSet,
+            File incomingFolderWithImages)
+    {
+        DataSetRegistrationDetails<ImageDataSetInformation> details =
+                SimpleImageDataSetRegistrator.createImageDatasetDetails(imageDataSet,
+                        incomingFolderWithImages, imageDatasetFactory);
+        return createNewOverviewImageDataSet(details);
+    }
+
+    public IDataSet createNewFeatureListDataSet(FeatureListDataConfig config)
+    {
+        IDataSet dataSet = createNewDataSet();
+
+        dataSet.setDataSetType(ScreeningConstants.ANALYSIS_FEATURE_LIST);
+
+        IDataSetUpdatable container = config.getContainerDataSet();
+
+        verifyFeatureVectorContainer(container);
+
+        addNewDataSetToContainer(dataSet, container);
+
+        dataSet.setExperiment(container.getExperiment());
+
+        storeFeatureListInDataset(config, dataSet);
+
+        return dataSet;
+    }
+
+    private void storeFeatureListInDataset(FeatureListDataConfig config, IDataSet dataSet)
+    {
+        try
+        {
+            File directory =
+                    new File(getIncoming().getParentFile().getAbsolutePath(),
+                            ScreeningConstants.ANALYSIS_FEATURE_LIST_TOP_LEVEL_DIRECTORY_NAME);
+            directory.mkdirs();
+
+            File file = new File(directory, config.getName());
+            file.createNewFile();
+
+            BufferedWriter bw = new BufferedWriter(new FileWriter(file));
+
+            for (String feature : config.getFeatureList())
+            {
+                bw.append(feature);
+                bw.newLine();
+            }
+
+            bw.close();
+
+            moveFile(directory.getAbsolutePath(), dataSet);
+
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    private void addNewDataSetToContainer(IDataSet dataSet, IDataSetUpdatable container)
+    {
+        List<String> contained = new LinkedList<String>(container.getContainedDataSetCodes());
+        contained.add(dataSet.getDataSetCode());
+        container.setContainedDataSetCodes(contained);
+    }
+
+    private void verifyFeatureVectorContainer(IDataSetUpdatable container)
+    {
+        if (container == null)
+        {
+            throw new UserFailureException(
+                    "Setting of container dataset for feature list data set is obligatory");
+        }
+
+        if (false == container.getDataSetType().startsWith(
+                ScreeningConstants.HCS_ANALYSIS_ANY_CONTAINER_DATASET_TYPE_PREFIX))
+        {
+            throw new UserFailureException(
+                    "Container for feature list must be of HCS_ANALYSIS_CONTAINER.* type");
+        }
+    }
+
+    /**
+     * Creates new container dataset which contains one feature vector dataset.
+     */
+    public FeatureVectorContainerDataSet createNewFeatureVectorDataSet(
+            SimpleFeatureVectorDataConfig featureDataSetConfig, File featureVectorFileOrNull)
+    {
+        DataSetRegistrationDetails<FeatureVectorDataSetInformation> registrationDetails =
+                createFeatureVectorDataSetRegistrationDetails(featureDataSetConfig,
+                        featureVectorFileOrNull);
+        return createFeatureVectorDataSet(registrationDetails);
+    }
+
+    private FeatureVectorContainerDataSet createFeatureVectorDataSet(
+            DataSetRegistrationDetails<FeatureVectorDataSetInformation> registrationDetails)
+    {
+        @SuppressWarnings("unchecked")
+        DataSet<FeatureVectorDataSetInformation> dataSet =
+                (DataSet<FeatureVectorDataSetInformation>) super
+                        .createNewDataSet(registrationDetails);
+
+        FeatureVectorDataSet featureDataset =
+                new FeatureVectorDataSet(dataSet, getGlobalState().getOpenBisService());
+
+        // create container
+        FeatureVectorContainerDataSet containerDataset =
+                createFeatureVectorContainerDataSet(featureDataset);
+
+        registrationDetails.getDataSetInformation().setContainerDatasetPermId(
+                containerDataset.getDataSetCode());
+
+        return containerDataset;
+    }
+
+    private DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorDataSetRegistrationDetails(
+            SimpleFeatureVectorDataConfig featureDataSetConfig, File featureVectorFileOrNull)
+    {
+        List<FeatureDefinition> featureDefinitions;
+        Properties properties = featureDataSetConfig.getProperties();
+        if (properties == null)
+        {
+            featureDefinitions =
+                    ((FeaturesBuilder) featureDataSetConfig.getFeaturesBuilder())
+                            .getFeatureDefinitionValuesList();
+        } else
+        {
+            try
+            {
+                featureDefinitions =
+                        CsvFeatureVectorParser.parse(featureVectorFileOrNull, properties);
+            } catch (IOException ex)
+            {
+                throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+            }
+        }
+        DataSetRegistrationDetails<FeatureVectorDataSetInformation> registrationDetails =
+                factory.createFeatureVectorRegistrationDetails(featureDefinitions);
+        return registrationDetails;
+    }
+
+    /**
+     * Creates container dataset which contains dataset with original images (created on the fly).
+     * If thumbnails are required they are generated and moved to a thumbnail dataset which becomes
+     * a part of the container as well.
+     * <p>
+     * The original images dataset is special - it contains description of what should be saved in
+     * imaging database by the storage processor.
+     * 
+     * @return container dataset.
+     */
+    public IImageDataSet createNewImageDataSet(
+            DataSetRegistrationDetails<ImageDataSetInformation> imageRegistrationDetails)
+    {
+        ImageDataSetInformation imageDataSetInformation =
+                imageRegistrationDetails.getDataSetInformation();
+        ImageDataSetStructure imageDataSetStructure =
+                imageDataSetInformation.getImageDataSetStructure();
+        File incomingDirectory = imageDataSetInformation.getIncomingDirectory();
+        List<String> containedDataSetCodes = new ArrayList<String>();
+
+        // Compute the bounding box of the images -- needs to happen before thumbnail
+        // generation, since thumbnails may want to know the bounding box
+        calculateBoundingBox(imageDataSetInformation, imageDataSetStructure, incomingDirectory);
+
+        // create thumbnails dataset if needed
+        List<IDataSet> thumbnailDatasets = new ArrayList<IDataSet>();
+        boolean generateThumbnails = imageDataSetStructure.areThumbnailsGenerated();
+        if (generateThumbnails)
+        {
+            imageDataSetStructure
+                    .validateImageRepresentationGenerationParameters(imageDataSetInformation);
+
+            List<ThumbnailsStorageFormat> thumbnailsStorageFormatList =
+                    imageDataSetStructure.getImageStorageConfiguraton()
+                            .getThumbnailsStorageFormat();
+
+            ThumbnailsInfo thumbnailsInfo = new ThumbnailsInfo();
+            for (ThumbnailsStorageFormat thumbnailsStorageFormat : thumbnailsStorageFormatList)
+            {
+                IDataSet thumbnailDataset =
+                        createThumbnailDataset(imageDataSetInformation, thumbnailsStorageFormat);
+                thumbnailDatasets.add(thumbnailDataset);
+
+                generateThumbnails(imageDataSetStructure, incomingDirectory, thumbnailDataset,
+                        thumbnailsStorageFormat, thumbnailsInfo, false, null);
+                containedDataSetCodes.add(thumbnailDataset.getDataSetCode());
+            }
+            imageDataSetInformation.setThumbnailsInfo(thumbnailsInfo);
+        }
+
+        // create main dataset (with original images)
+        @SuppressWarnings("unchecked")
+        DataSet<ImageDataSetInformation> mainDataset =
+                (DataSet<ImageDataSetInformation>) super.createNewDataSet(imageRegistrationDetails);
+        containedDataSetCodes.add(mainDataset.getDataSetCode());
+
+        for (IDataSet thumbnailDataset : thumbnailDatasets)
+        {
+            setSameDatasetOwner(mainDataset, thumbnailDataset);
+        }
+        ImageContainerDataSet containerDataset =
+                createImageContainerDataset(mainDataset, imageDataSetInformation,
+                        containedDataSetCodes);
+        containerDataset.setOriginalDataset(mainDataset);
+        for (IDataSet thumbnailDataset : thumbnailDatasets)
+        {
+            containerDataset.setThumbnailDatasets(Arrays.asList(thumbnailDataset));
+        }
+        imageDataSetInformation.setContainerDatasetPermId(containerDataset.getDataSetCode());
+
+        return containerDataset;
+    }
+
+    @SuppressWarnings("unchecked")
+    private IDataSet createNewOverviewImageDataSet(
+            DataSetRegistrationDetails<ImageDataSetInformation> imageRegistrationDetails)
+    {
+        ImageDataSetInformation imageDataSetInformation =
+                imageRegistrationDetails.getDataSetInformation();
+        ImageDataSetStructure imageDataSetStructure =
+                imageDataSetInformation.getImageDataSetStructure();
+        File incomingDirectory = imageDataSetInformation.getIncomingDirectory();
+
+        String containerCode = imageDataSetInformation.tryGetContainerDatasetPermId();
+
+        IDataSetUpdatable container = getDataSetForUpdate(containerCode);
+
+        if (container == null || false == container.isContainerDataSet())
+        {
+            throw UserFailureException.fromTemplate("Container data set %s coudn't be found.",
+                    container);
+        }
+
+        calculateBoundingBox(imageDataSetInformation, imageDataSetStructure, incomingDirectory);
+
+        SearchCriteria searchCriteria = new SearchCriteria();
+        SearchCriteria searchSubCriteria = new SearchCriteria();
+        searchSubCriteria.addMatchClause(MatchClause.createAttributeMatch(
+                MatchClauseAttribute.CODE, containerCode));
+        searchCriteria.addSubCriteria(SearchSubCriteria
+                .createDataSetContainerCriteria(searchSubCriteria));
+
+        List<IDataSetImmutable> containedDataSets =
+                getSearchService().searchForDataSets(searchCriteria);
+
+        IDataSetImmutable exampleDataSet = containedDataSets.iterator().next();
+
+        imageDataSetStructure
+                .validateImageRepresentationGenerationParameters(imageDataSetInformation);
+
+        ThumbnailsInfo thumbnailsInfo = new ThumbnailsInfo();
+        List<String> containedDataSetCodes = new ArrayList<String>();
+        containedDataSetCodes.addAll(container.getContainedDataSetCodes());
+
+        List<IDataSet> thumbnailDatasets = new ArrayList<IDataSet>();
+        if (imageDataSetInformation.isGenerateOverviewImagesFromRegisteredImages())
+        {
+            IHierarchicalContent content =
+                    ServiceProvider.getHierarchicalContentProvider().asContent(containerCode);
+            try
+            {
+                imageDataSetStructure
+                        .validateImageRepresentationGenerationParameters(imageDataSetInformation);
+
+                List<ThumbnailsStorageFormat> thumbnailsStorageFormatList =
+                        imageDataSetStructure.getImageStorageConfiguraton()
+                                .getThumbnailsStorageFormat();
+
+                boolean isFirst = true;
+                for (ThumbnailsStorageFormat thumbnailsStorageFormat : thumbnailsStorageFormatList)
+                {
+                    IDataSet thumbnailDataset = null;
+                    if (isFirst)
+                    {
+                        thumbnailDataset = super.createNewDataSet(imageRegistrationDetails);
+                        thumbnailDataset.setFileFormatType(thumbnailsStorageFormat.getFileFormat()
+                                .getOpenBISFileType());
+                        thumbnailDataset.setMeasuredData(false);
+                        isFirst = false;
+                    } else
+                    {
+                        thumbnailDataset =
+                                createThumbnailDataset(imageDataSetInformation,
+                                        thumbnailsStorageFormat);
+
+                    }
+                    thumbnailDatasets.add(thumbnailDataset);
+
+                    generateThumbnails(imageDataSetStructure, incomingDirectory, thumbnailDataset,
+                            thumbnailsStorageFormat, thumbnailsInfo, false, content);
+                    containedDataSetCodes.add(thumbnailDataset.getDataSetCode());
+                }
+            } finally
+            {
+                if (content != null)
+                {
+                    content.close();
+                }
+            }
+        } else
+        {
+            DataSet<ImageDataSetInformation> thumbnailDataset =
+                    (DataSet<ImageDataSetInformation>) super
+                            .createNewDataSet(imageRegistrationDetails);
+            thumbnailDataset.setFileFormatType(imageDataSetInformation.getFileFormatTypeCode());
+            thumbnailDataset.setMeasuredData(false);
+            thumbnailDatasets.add(thumbnailDataset);
+
+            generateThumbnails(imageDataSetStructure, incomingDirectory, thumbnailDataset,
+                    createThumbnailsStorageFormat(imageDataSetInformation), thumbnailsInfo, true,
+                    null);
+            containedDataSetCodes.add(thumbnailDataset.getDataSetCode());
+        }
+
+        imageDataSetInformation.setThumbnailsInfo(thumbnailsInfo);
+
+        for (IDataSet thumbnailDataset : thumbnailDatasets)
+        {
+            setSameDatasetOwner(exampleDataSet, thumbnailDataset);
+        }
+
+        container.setContainedDataSetCodes(containedDataSetCodes);
+
+        return thumbnailDatasets.iterator().next();
+    }
+
+    private static ThumbnailsStorageFormat createThumbnailsStorageFormat(
+            ImageDataSetInformation imageDataSetInformation)
+    {
+        ThumbnailsStorageFormat thumbnailsStorageFormat = new ThumbnailsStorageFormat();
+
+        thumbnailsStorageFormat.setFileFormat(imageDataSetInformation.getFileFormatTypeCode());
+        thumbnailsStorageFormat.setThumbnailsFileName(String.format("thumbnails_%dx%d.h5ar",
+                imageDataSetInformation.getMaximumImageWidth(),
+                imageDataSetInformation.getMaximumImageHeight()));
+
+        return thumbnailsStorageFormat;
+    }
+
+    private void calculateBoundingBox(ImageDataSetInformation imageDataSetInformation,
+            ImageDataSetStructure imageDataSetStructure, File incomingDirectory)
+    {
+        ImageLibraryInfo imageLibrary =
+                imageDataSetStructure.getImageStorageConfiguraton().tryGetImageLibrary();
+        List<ImageFileInfo> images = imageDataSetStructure.getImages();
+
+        if (imageDataSetInformation.isGenerateOverviewImagesFromRegisteredImages())
+        {
+            IHierarchicalContent content =
+                    ServiceProvider.getHierarchicalContentProvider().asContent(
+                            imageDataSetInformation.tryGetContainerDatasetPermId());
+            try
+            {
+                for (ImageFileInfo imageFileInfo : images)
+                {
+                    Size size =
+                            Utils.loadUnchangedImageSize(
+                                    content.getNode(imageFileInfo.getImageRelativePath()), null,
+                                    imageLibrary);
+                    imageDataSetInformation.setMaximumImageWidth(Math.max(
+                            imageDataSetInformation.getMaximumImageWidth(), size.getWidth()));
+                    imageDataSetInformation.setMaximumImageHeight(Math.max(
+                            imageDataSetInformation.getMaximumImageHeight(), size.getHeight()));
+                }
+            } finally
+            {
+                if (content != null)
+                {
+                    content.close();
+                }
+            }
+        } else
+        {
+            for (ImageFileInfo imageFileInfo : images)
+            {
+                File file = new File(incomingDirectory, imageFileInfo.getImageRelativePath());
+                Size size =
+                        Utils.loadUnchangedImageSize(new FileBasedContentNode(file), null,
+                                imageLibrary);
+                imageDataSetInformation.setMaximumImageWidth(Math.max(
+                        imageDataSetInformation.getMaximumImageWidth(), size.getWidth()));
+                imageDataSetInformation.setMaximumImageHeight(Math.max(
+                        imageDataSetInformation.getMaximumImageHeight(), size.getHeight()));
+            }
+        }
+    }
+
+    private File prependOriginalDirectory(String directoryPath)
+    {
+        return new File(originalDirName + File.separator + directoryPath);
+    }
+
+    private void generateThumbnails(ImageDataSetStructure imageDataSetStructure,
+            File incomingDirectory, IDataSet thumbnailDataset,
+            ThumbnailsStorageFormat thumbnailsStorageFormatOrNull, ThumbnailsInfo thumbnailPaths,
+            boolean registerOriginalImageAsThumbnail, IHierarchicalContent content)
+    {
+        String thumbnailFile;
+        if (thumbnailsStorageFormatOrNull == null)
+        {
+            thumbnailFile =
+                    createNewFile(thumbnailDataset, Constants.HDF5_CONTAINER_THUMBNAILS_FILE_NAME);
+        } else
+        {
+            thumbnailFile =
+                    createNewFile(thumbnailDataset,
+                            thumbnailsStorageFormatOrNull.getThumbnailsFileName());
+        }
+
+        Hdf5ThumbnailGenerator.tryGenerateThumbnails(imageDataSetStructure, incomingDirectory,
+                thumbnailFile, imageDataSetStructure.getImageStorageConfiguraton(),
+                thumbnailDataset.getDataSetCode(), thumbnailsStorageFormatOrNull, thumbnailPaths,
+                registerOriginalImageAsThumbnail, content);
+        enhanceWithResolution(thumbnailDataset, thumbnailPaths);
+    }
+
+    private static void enhanceWithResolution(IDataSet thumbnailDataset,
+            ThumbnailsInfo thumbnailPaths)
+    {
+        Size size = thumbnailPaths.tryGetDimension(thumbnailDataset.getDataSetCode());
+        if (size != null)
+        {
+            thumbnailDataset.setPropertyValue(ScreeningConstants.RESOLUTION, size.getWidth() + "x"
+                    + size.getHeight());
+        }
+    }
+
+    private IDataSet createThumbnailDataset(DataSetInformation imageDataSetInformation,
+            ThumbnailsStorageFormat thumbnailsStorageFormat)
+    {
+        String thumbnailsDatasetTypeCode = findThumbnailsDatasetTypeCode(imageDataSetInformation);
+        IDataSet thumbnailDataset = createNewDataSet(thumbnailsDatasetTypeCode);
+        thumbnailDataset.setFileFormatType(thumbnailsStorageFormat.getFileFormat()
+                .getOpenBISFileType());
+        thumbnailDataset.setMeasuredData(false);
+
+        return thumbnailDataset;
+    }
+
+    private ImageContainerDataSet createImageContainerDataset(IDataSet mainDataset,
+            DataSetInformation imageDataSetInformation, List<String> containedDataSetCodes)
+    {
+        String containerDatasetTypeCode = findContainerDatasetTypeCode(imageDataSetInformation);
+        @SuppressWarnings("unchecked")
+        ImageContainerDataSet containerDataset =
+                (ImageContainerDataSet) createNewDataSet(imageContainerDatasetFactory,
+                        containerDatasetTypeCode);
+        setSameDatasetOwner(mainDataset, containerDataset);
+        moveDatasetRelations(mainDataset, containerDataset);
+
+        containerDataset.setContainedDataSetCodes(containedDataSetCodes);
+        return containerDataset;
+    }
+
+    private FeatureVectorContainerDataSet createFeatureVectorContainerDataSet(
+            FeatureVectorDataSet mainDataset)
+    {
+        String containerDatasetTypeCode =
+                FeatureVectorContainerDataSet
+                        .getContainerAnalysisType(mainDataset.getDataSetType());
+
+        @SuppressWarnings("unchecked")
+        FeatureVectorContainerDataSet containerDataSet =
+                (FeatureVectorContainerDataSet) createNewDataSet(
+                        factory.featureVectorContainerDatasetFactory, containerDatasetTypeCode);
+        containerDataSet.setContainedDataSetCodes(Collections.singletonList(mainDataset
+                .getDataSetCode()));
+
+        containerDataSet.setOriginalDataSet(mainDataset);
+
+        return containerDataSet;
+    }
+
+    // Copies properties and relations to datasets from the main dataset to the container and
+    // resets them in the main dataset.
+    private static void moveDatasetRelations(IDataSet mainDataset, IDataSet containerDataset)
+    {
+        containerDataset.setParentDatasets(mainDataset.getParentDatasets());
+        mainDataset.setParentDatasets(Collections.<String> emptyList());
+
+        for (String propertyCode : mainDataset.getAllPropertyCodes())
+        {
+            containerDataset.setPropertyValue(propertyCode,
+                    mainDataset.getPropertyValue(propertyCode));
+            mainDataset.setPropertyValue(propertyCode, null);
+        }
+    }
+
+    private static boolean isHCSImageDataSetType(String mainDatasetTypeCode)
+    {
+        String prefix = ScreeningConstants.HCS_IMAGE_DATASET_TYPE_PREFIX;
+        if (mainDatasetTypeCode.startsWith(prefix))
+        {
+            if (mainDatasetTypeCode
+                    .contains(ScreeningConstants.IMAGE_CONTAINER_DATASET_TYPE_MARKER))
+            {
+                throw UserFailureException
+                        .fromTemplate(
+                                "The specified image dataset type '%s' should not be of container type, but contains '%s' in the type code.",
+                                mainDatasetTypeCode,
+                                ScreeningConstants.IMAGE_CONTAINER_DATASET_TYPE_MARKER);
+            }
+            return true;
+        } else
+        {
+            return false;
+        }
+    }
+
+    private static boolean isMicroscopyImageDataSetType(String dataSetTypeCode)
+    {
+        return dataSetTypeCode.contains(MICROSCOPY_IMAGE_TYPE_SUBSTRING)
+                && false == dataSetTypeCode.contains(MICROSCOPY_CONTAINER_TYPE_SUBSTRING);
+    }
+
+    private static String findContainerDatasetTypeCode(DataSetInformation imageDataSetInformation)
+    {
+        String dataSetTypeCode = imageDataSetInformation.getDataSetType().getCode().toUpperCase();
+        String prefix = ScreeningConstants.HCS_IMAGE_DATASET_TYPE_PREFIX;
+        if (isHCSImageDataSetType(dataSetTypeCode))
+        {
+            return prefix + ScreeningConstants.IMAGE_CONTAINER_DATASET_TYPE_MARKER
+                    + dataSetTypeCode.substring(prefix.length());
+        } else if (isMicroscopyImageDataSetType(dataSetTypeCode))
+        {
+            return dataSetTypeCode.replace(MICROSCOPY_IMAGE_TYPE_SUBSTRING,
+                    MICROSCOPY_CONTAINER_TYPE_SUBSTRING);
+        } else
+        {
+            throw UserFailureException
+                    .fromTemplate(
+                            "The image dataset type '%s' is neither standard HCS type (starts with '%s') nor a microscopy type (contains '%s').",
+                            dataSetTypeCode, prefix,
+                            ScreeningConstants.MICROSCOPY_IMAGE_SAMPLE_TYPE_PATTERN);
+        }
+    }
+
+    private static String findThumbnailsDatasetTypeCode(DataSetInformation imageDataSetInformation)
+    {
+        String dataSetTypeCode = imageDataSetInformation.getDataSetType().getCode().toUpperCase();
+
+        if (isHCSImageDataSetType(dataSetTypeCode))
+        {
+            return ScreeningConstants.HCS_IMAGE_DATASET_TYPE_PREFIX
+                    + ScreeningConstants.IMAGE_THUMBNAIL_DATASET_TYPE_MARKER;
+        } else if (isMicroscopyImageDataSetType(dataSetTypeCode))
+        {
+            return dataSetTypeCode.replace(ScreeningConstants.MICROSCOPY_IMAGE_TYPE_SUBSTRING,
+                    ScreeningConstants.MICROSCOPY_THUMBNAIL_TYPE_SUBSTRING);
+        } else
+        {
+            throw UserFailureException
+                    .fromTemplate(
+                            "The image dataset type '%s' is neither standard HCS type (starts with '%s') nor a microscopy type (contains '%s').",
+                            dataSetTypeCode, ScreeningConstants.HCS_IMAGE_DATASET_TYPE_PREFIX,
+                            ScreeningConstants.MICROSCOPY_IMAGE_SAMPLE_TYPE_PATTERN);
+        }
+    }
+
+    private static void setSameDatasetOwner(IDataSetImmutable templateDataset,
+            IDataSet destinationDataset)
+    {
+        destinationDataset.setExperiment(templateDataset.getExperiment());
+        destinationDataset.setSample(templateDataset.getSample());
+
+    }
+
+    @SuppressWarnings(
+        { "cast", "unchecked" })
+    @Override
+    public IDataSet createNewDataSet(DataSetRegistrationDetails registrationDetails)
+    {
+        if (registrationDetails.getDataSetInformation() instanceof ImageDataSetInformation)
+        {
+            DataSetRegistrationDetails<ImageDataSetInformation> imageRegistrationDetails =
+                    (DataSetRegistrationDetails<ImageDataSetInformation>) registrationDetails;
+            return createNewImageDataSet(imageRegistrationDetails);
+        } else if (registrationDetails.getDataSetInformation() instanceof FeatureVectorDataSetInformation)
+        {
+            DataSetRegistrationDetails<FeatureVectorDataSetInformation> featureRegistrationDetails =
+                    (DataSetRegistrationDetails<FeatureVectorDataSetInformation>) registrationDetails;
+            return createFeatureVectorDataSet(featureRegistrationDetails);
+        } else
+        {
+            return super.createNewDataSet(registrationDetails);
+        }
+    }
+
+    /**
+     * If we are dealing with the image dataset container then the move operation is delegated to
+     * the original dataset. Otherwise a default implementation is used.
+     */
+    @Override
+    public String moveFile(String src, IDataSet dst)
+    {
+        System.out.println("MF:" + src);
+
+        return moveFile(src, dst, new File(src).getName());
+    }
+
+    /**
+     * If we are dealing with the image dataset container then the move operation is delegated to
+     * the original dataset. Otherwise a default implementation is used.
+     */
+    @Override
+    public String moveFile(String src, IDataSet dst, String dstInDataset)
+    {
+        System.out.println("MF3:" + dstInDataset);
+
+        ImageContainerDataSet imageContainerDataset = tryAsImageContainerDataset(dst);
+
+        if (imageContainerDataset != null)
+        {
+            String destination = getDestinationInOriginal(dstInDataset);
+            DataSet<ImageDataSetInformation> originalDataset =
+                    imageContainerDataset.getOriginalDataset();
+            if (originalDataset == null)
+            {
+                throw new UserFailureException(
+                        "Cannot move the files because the original dataset is missing: " + src);
+            }
+            originalDataset.getRegistrationDetails().getDataSetInformation()
+                    .setDatasetRelativeImagesFolderPath(new File(destination));
+
+            return super.moveFile(src, originalDataset, destination);
+        }
+
+        FeatureVectorContainerDataSet featureContainer = tryAsFeatureVectorContainerDataset(dst);
+        if (featureContainer != null)
+        {
+            IDataSet originalDataSet = featureContainer.getOriginalDataset();
+
+            if (originalDataSet == null)
+            {
+                throw new UserFailureException(
+                        "Cannot move the files because the original dataset is missing: " + src);
+            }
+
+            return super.moveFile(src, originalDataSet, dstInDataset);
+        }
+
+        return super.moveFile(src, dst, dstInDataset);
+    }
+
+    private String getDestinationInOriginal(String dstInDataset)
+    {
+        String destination = dstInDataset;
+        if (destination.startsWith(originalDirName) == false)
+        {
+            destination = prependOriginalDirectory(destination).getPath();
+        }
+        return destination;
+    }
+
+    private static FeatureVectorContainerDataSet tryAsFeatureVectorContainerDataset(IDataSet dataset)
+    {
+        if (dataset instanceof FeatureVectorContainerDataSet)
+        {
+            return (FeatureVectorContainerDataSet) dataset;
+        }
+        return null;
+    }
+
+    private static ImageContainerDataSet tryAsImageContainerDataset(IDataSet dataset)
+    {
+        if (dataset instanceof ImageContainerDataSet)
+        {
+            return (ImageContainerDataSet) dataset;
+        } else
+        {
+            return null;
+        }
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransactionV2Delegate.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransactionV2Delegate.java
index 9f524cfb849a55c73d84499c567edc04e25434f8..535108642ae3c228c53ad0d3f7716ec64d93edee 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransactionV2Delegate.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransactionV2Delegate.java
@@ -22,34 +22,33 @@ import net.lemnik.eodsql.DynamicTransactionQuery;
 
 import ch.systemsx.cisd.etlserver.TopLevelDataSetRegistratorGlobalState;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationContext;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetUpdatable;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IExperiment;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IExperimentUpdatable;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IMaterial;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IMetaproject;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IProject;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.ISample;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.ISpace;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IVocabulary;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IVocabularyTerm;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IImageDataSet;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSetUpdatable;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IExperiment;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IExperimentUpdatable;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IMaterial;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IMetaproject;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IProject;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.ISample;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.ISpace;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IVocabulary;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IVocabularyTerm;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.FeatureListDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IFeatureVectorDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IImageDataSet;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IImagingDataSetRegistrationTransactionV2;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.SimpleFeatureVectorDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.jython.ImagingDataSetRegistrationTransaction;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IDataSetImmutable;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IExperimentImmutable;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IExternalDataManagementSystemImmutable;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IMaterialImmutable;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IProjectImmutable;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.ISampleImmutable;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.ISearchService;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.ISpaceImmutable;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IVocabularyImmutable;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.authorization.IAuthorizationService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IDataSetImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IExperimentImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IExternalDataManagementSystemImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IMaterialImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IProjectImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISampleImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISearchService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISpaceImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IVocabularyImmutable;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.authorization.IAuthorizationService;
 
 /**
  * @author Jakub Straszewski
@@ -148,8 +147,7 @@ public class ImagingDataSetRegistrationTransactionV2Delegate implements
     }
 
     @Override
-    public ISample createNewSampleWithGeneratedCode(String spaceCode,
-            String sampleTypeCode)
+    public ISample createNewSampleWithGeneratedCode(String spaceCode, String sampleTypeCode)
     {
         return transaction.createNewSampleWithGeneratedCode(spaceCode, sampleTypeCode);
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonImageContainerDataSetRegistrationFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonImageContainerDataSetRegistrationFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..075d56b230812432a6ce9353bd0a1921d1022ad4
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonImageContainerDataSetRegistrationFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 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.etl.jython.v2;
+
+import java.io.File;
+
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.v2.AbstractDataSetRegistrationDetailsFactory;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.impl.ImageContainerDataSet;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+
+/**
+ * @author jakubs
+ */
+public class JythonImageContainerDataSetRegistrationFactory extends
+        AbstractDataSetRegistrationDetailsFactory<DataSetInformation>
+{
+
+    public JythonImageContainerDataSetRegistrationFactory(
+            ch.systemsx.cisd.etlserver.registrator.v2.AbstractOmniscientTopLevelDataSetRegistrator.OmniscientTopLevelDataSetRegistratorState registratorState,
+            DataSetInformation userProvidedDataSetInformationOrNull)
+    {
+        super(registratorState, userProvidedDataSetInformationOrNull);
+    }
+
+    @Override
+    public ImageContainerDataSet createDataSet(
+            DataSetRegistrationDetails<DataSetInformation> registrationDetails, File stagingFile)
+    {
+        IEncapsulatedOpenBISService service = registratorState.getGlobalState().getOpenBisService();
+        return new ImageContainerDataSet(registrationDetails, stagingFile, service);
+    }
+
+    @Override
+    protected DataSetInformation createDataSetInformation()
+    {
+        return new DataSetInformation();
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonImageDataSetRegistrationFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonImageDataSetRegistrationFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ff12a87b10749d6e4fcf2dfeda81632c3a12cef
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonImageDataSetRegistrationFactory.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012 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.etl.jython.v2;
+
+import ch.systemsx.cisd.etlserver.registrator.v2.AbstractDataSetRegistrationDetailsFactory;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+
+/**
+ * @author jakubs
+ */
+public class JythonImageDataSetRegistrationFactory extends
+        AbstractDataSetRegistrationDetailsFactory<ImageDataSetInformation>
+{
+
+    public JythonImageDataSetRegistrationFactory(
+            ch.systemsx.cisd.etlserver.registrator.v2.AbstractOmniscientTopLevelDataSetRegistrator.OmniscientTopLevelDataSetRegistratorState registratorState,
+            DataSetInformation userProvidedDataSetInformationOrNull)
+    {
+        super(registratorState, userProvidedDataSetInformationOrNull);
+    }
+
+    @Override
+    protected ImageDataSetInformation createDataSetInformation()
+    {
+        return new ImageDataSetInformation();
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDataSetHandlerUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDataSetHandlerUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..e89cf3e04cc124880e8a4349556211c4f8b235c8
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDataSetHandlerUtils.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 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.etl.jython.v2;
+
+import java.util.Properties;
+
+import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
+import ch.systemsx.cisd.common.properties.PropertyUtils;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
+
+/**
+ * 
+ *
+ * @author jakubs
+ */
+public class JythonPlateDataSetHandlerUtils
+{
+    private static final String ORIGINAL_DIRNAME_KEY = "image-datasets-original-dir-name";
+
+    public static String parseOriginalDir(Properties threadProperties)
+    {
+        String originalDir =
+                PropertyUtils.getProperty(threadProperties, ORIGINAL_DIRNAME_KEY,
+                        ScreeningConstants.ORIGINAL_DATA_DIR);
+        if (false == FileUtilities.isValidFileName(originalDir))
+        {
+            throw ConfigurationFailureException.fromTemplate(
+                    "Invalid folder name specified in '%s': '%s'.", ORIGINAL_DIRNAME_KEY,
+                    originalDir);
+        }
+        return originalDir;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDataSetHandlerV2.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDataSetHandlerV2.java
index d8953d16315aa1a294c38b4e16e4d14d456e9175..757015700954ea983c638dbb66670b8d80870893 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDataSetHandlerV2.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDataSetHandlerV2.java
@@ -23,17 +23,12 @@ import ch.systemsx.cisd.common.jython.PythonInterpreter;
 import ch.systemsx.cisd.etlserver.ITopLevelDataSetRegistratorDelegate;
 import ch.systemsx.cisd.etlserver.TopLevelDataSetRegistratorGlobalState;
 import ch.systemsx.cisd.etlserver.registrator.DataSetFile;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSetRegistrationTransaction;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSetRegistrationTransaction;
 import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSetRegistrationTransactionV2;
 import ch.systemsx.cisd.etlserver.registrator.api.v2.JythonDataSetRegistrationServiceV2;
 import ch.systemsx.cisd.etlserver.registrator.api.v2.JythonTopLevelDataSetHandlerV2;
-import ch.systemsx.cisd.etlserver.registrator.recovery.AutoRecoverySettings;
-import ch.systemsx.cisd.etlserver.registrator.v1.DataSetRegistrationService;
-import ch.systemsx.cisd.etlserver.registrator.v1.IDataSetRegistrationDetailsFactory;
-import ch.systemsx.cisd.openbis.dss.etl.jython.ImagingDataSetRegistrationTransaction;
-import ch.systemsx.cisd.openbis.dss.etl.jython.JythonPlateDataSetHandlerUtils;
-import ch.systemsx.cisd.openbis.dss.etl.jython.JythonPlateDatasetFactory;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSetRegistrationTransaction;
+import ch.systemsx.cisd.etlserver.registrator.v2.DataSetRegistrationService;
+import ch.systemsx.cisd.etlserver.registrator.v2.IDataSetRegistrationDetailsFactory;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 
 /**
@@ -77,7 +72,7 @@ public class JythonPlateDataSetHandlerV2 extends JythonTopLevelDataSetHandlerV2<
             {
                 @SuppressWarnings("unchecked")
                 @Override
-                protected DataSetRegistrationTransaction<DataSetInformation> createV2DatasetRegistrationTransaction(
+                protected DataSetRegistrationTransaction<DataSetInformation> createTransaction(
                         File rollBackStackParentFolder,
                         File workingDirectory,
                         File stagingDirectory,
@@ -85,14 +80,14 @@ public class JythonPlateDataSetHandlerV2 extends JythonTopLevelDataSetHandlerV2<
                 {
                     return new ImagingDataSetRegistrationTransaction(rollBackStackParentFolder,
                             workingDirectory, stagingDirectory, this, registrationDetailsFactory,
-                            originalDirName, AutoRecoverySettings.USE_AUTO_RECOVERY);
+                            originalDirName);
                 }
             };
     }
 
     @Override
     protected IDataSetRegistrationTransactionV2 wrapTransaction(
-            IDataSetRegistrationTransaction transaction)
+            DataSetRegistrationTransaction<DataSetInformation> transaction)
     {
         return new ImagingDataSetRegistrationTransactionV2Delegate(
                 (ImagingDataSetRegistrationTransaction) transaction);
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDatasetFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDatasetFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..972213024b940ce9f714d300ede92bb6e63895e1
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/JythonPlateDatasetFactory.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2012 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.etl.jython.v2;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.JythonTopLevelDataSetHandlerV2.ProgrammableDropboxObjectFactory;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSetRegistrationTransaction;
+import ch.systemsx.cisd.etlserver.registrator.v2.AbstractOmniscientTopLevelDataSetRegistrator.OmniscientTopLevelDataSetRegistratorState;
+import ch.systemsx.cisd.etlserver.registrator.v2.DataSetRegistrationService;
+import ch.systemsx.cisd.etlserver.registrator.v2.IDataSetRegistrationDetailsFactory;
+import ch.systemsx.cisd.openbis.dss.etl.PlateGeometryOracle;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IFeaturesBuilder;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureDefinition;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeaturesBuilder;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IImagingDatasetFactory;
+import ch.systemsx.cisd.openbis.dss.etl.featurevector.CsvFeatureVectorParser;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
+
+/**
+ * @author jakubs
+ */
+
+public class JythonPlateDatasetFactory extends ProgrammableDropboxObjectFactory<DataSetInformation>
+        implements IImagingDatasetFactory
+{
+    final IDataSetRegistrationDetailsFactory<ImageDataSetInformation> imageDatasetFactory;
+
+    final IDataSetRegistrationDetailsFactory<DataSetInformation> imageContainerDatasetFactory;
+
+    final IDataSetRegistrationDetailsFactory<DataSetInformation> featureVectorContainerDatasetFactory;
+
+    final IDataSetRegistrationDetailsFactory<FeatureVectorDataSetInformation> featureVectorDatasetFactory;
+
+    public JythonPlateDatasetFactory(OmniscientTopLevelDataSetRegistratorState registratorState,
+            DataSetInformation userProvidedDataSetInformationOrNull)
+    {
+        super(registratorState, userProvidedDataSetInformationOrNull);
+        this.imageContainerDatasetFactory =
+                new JythonImageContainerDataSetRegistrationFactory(this.registratorState,
+                        this.userProvidedDataSetInformationOrNull);
+        this.imageDatasetFactory =
+                new JythonImageDataSetRegistrationFactory(this.registratorState,
+                        this.userProvidedDataSetInformationOrNull);
+        this.featureVectorDatasetFactory =
+                new ProgrammableDropboxObjectFactory<FeatureVectorDataSetInformation>(
+                        this.registratorState, this.userProvidedDataSetInformationOrNull)
+                    {
+                        @Override
+                        protected FeatureVectorDataSetInformation createDataSetInformation()
+                        {
+                            return new FeatureVectorDataSetInformation();
+                        }
+                    };
+
+        this.featureVectorContainerDatasetFactory =
+                new FeatureVectorContainerDataSetRegistrationFactory(this.registratorState,
+                        this.userProvidedDataSetInformationOrNull);
+    }
+
+    /** By default a standard dataset is created. */
+    @Override
+    protected DataSetInformation createDataSetInformation()
+    {
+        return new DataSetInformation();
+    }
+
+    @Override
+    public DataSetRegistrationDetails<ImageDataSetInformation> createImageRegistrationDetails(
+            SimpleImageDataConfig imageDataSet, File incomingDatasetFolder)
+    {
+        return SimpleImageDataSetRegistrator.createImageDatasetDetails(imageDataSet,
+                incomingDatasetFolder, imageDatasetFactory);
+    }
+
+    /** a simple method to register the described image dataset in a separate transaction */
+    @Override
+    public boolean registerImageDataset(SimpleImageDataConfig imageDataSet,
+            File incomingDatasetFolder, DataSetRegistrationService<ImageDataSetInformation> service)
+    {
+        DataSetRegistrationDetails<ImageDataSetInformation> imageDatasetDetails =
+                createImageRegistrationDetails(imageDataSet, incomingDatasetFolder);
+        return registerImageDataset(imageDatasetDetails, incomingDatasetFolder, service);
+    }
+
+    @Override
+    public boolean registerImageDataset(
+            DataSetRegistrationDetails<ImageDataSetInformation> imageDatasetDetails,
+            File incomingDatasetFolder, DataSetRegistrationService<ImageDataSetInformation> service)
+    {
+        DataSetRegistrationTransaction<ImageDataSetInformation> transaction =
+                service.transaction(incomingDatasetFolder,
+                        service.getDataSetRegistrationDetailsFactory());
+        IDataSet newDataset = transaction.createNewDataSet(imageDatasetDetails);
+        transaction.moveFile(incomingDatasetFolder.getPath(), newDataset);
+        return transaction.commit();
+    }
+
+    /**
+     * @return a constant which can be used as a vocabulary term value for $PLATE_GEOMETRY property
+     *         of a plate/
+     * @throws UserFailureException if all available geometries in openBIS are too small (there is a
+     *             well outside).
+     */
+    @Override
+    public String figureGeometry(
+            DataSetRegistrationDetails<ImageDataSetInformation> registrationDetails)
+    {
+        IEncapsulatedOpenBISService openBisService =
+                registratorState.getGlobalState().getOpenBisService();
+        return PlateGeometryOracle.figureGeometry(registrationDetails, openBisService);
+    }
+
+    // ----
+
+    @Override
+    public IFeaturesBuilder createFeaturesBuilder()
+    {
+        return new FeaturesBuilder();
+    }
+
+    @Override
+    public DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorDatasetDetails(
+            IFeaturesBuilder featureBuilder)
+    {
+        FeaturesBuilder myFeatureBuilder = (FeaturesBuilder) featureBuilder;
+        List<FeatureDefinition> featureDefinitions =
+                myFeatureBuilder.getFeatureDefinitionValuesList();
+        return createFeatureVectorRegistrationDetails(featureDefinitions);
+    }
+
+    /**
+     * Parses the feature vectors from the specified CSV file. CSV format can be configured with
+     * following properties:
+     * 
+     * <pre>
+     *   # Separator character between headers and row cells.
+     *   separator = ,
+     *   ignore-comments = true
+     *   # Header of the column denoting the row of a well.
+     *   well-name-row = row
+     *   # Header of the column denoting the column of a well.
+     *   well-name-col = col
+     *   well-name-col-is-alphanum = true
+     * </pre>
+     * 
+     * @throws IOException if file cannot be parsed
+     */
+    @Override
+    public DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorDatasetDetails(
+            String csvFilePath, Properties properties) throws IOException
+    {
+        List<FeatureDefinition> featureDefinitions =
+                CsvFeatureVectorParser.parse(new File(csvFilePath), properties);
+        return createFeatureVectorRegistrationDetails(featureDefinitions);
+    }
+
+    public DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorRegistrationDetails(
+            List<FeatureDefinition> featureDefinitions)
+    {
+        DataSetRegistrationDetails<FeatureVectorDataSetInformation> registrationDetails =
+                featureVectorDatasetFactory.createDataSetRegistrationDetails();
+        FeatureVectorDataSetInformation featureVectorDataSet =
+                registrationDetails.getDataSetInformation();
+        featureVectorDataSet.setFeatures(featureDefinitions);
+        registrationDetails.setDataSetType(ScreeningConstants.DEFAULT_ANALYSIS_WELL_DATASET_TYPE);
+        registrationDetails.setMeasuredData(false);
+        return registrationDetails;
+    }
+
+    // -------- backward compatibility methods
+
+    /**
+     * This method exists just for backward compatibility. It used to have the second parameter,
+     * which is now ignored.
+     * 
+     * @deprecated use {@link #createFeatureVectorDatasetDetails(IFeaturesBuilder)} instead.
+     */
+    @Deprecated
+    public DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorRegistrationDetails(
+            IFeaturesBuilder featureBuilder, Object incomingDatasetFolder)
+    {
+        return createFeatureVectorDatasetDetails(featureBuilder);
+    }
+
+    /**
+     * @deprecated Changed to {@link #createFeatureVectorDatasetDetails(String, Properties)} due to
+     *             naming convention change.
+     */
+    @Deprecated
+    public DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorRegistrationDetails(
+            String csvFilePath, Properties properties) throws IOException
+    {
+        return createFeatureVectorDatasetDetails(csvFilePath, properties);
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/SimpleImageDataSetRegistrator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/SimpleImageDataSetRegistrator.java
new file mode 100644
index 0000000000000000000000000000000000000000..c028b44596367f2758d04fa0a480c9a6d8745b8d
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/SimpleImageDataSetRegistrator.java
@@ -0,0 +1,772 @@
+/*
+ * 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.dss.etl.jython.v2;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.log4j.Logger;
+
+import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.common.collection.CollectionUtils;
+import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.filesystem.FileOperations;
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
+import ch.systemsx.cisd.common.image.IntensityRescaling;
+import ch.systemsx.cisd.common.image.IntensityRescaling.Levels;
+import ch.systemsx.cisd.common.image.IntensityRescaling.PixelHistogram;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
+import ch.systemsx.cisd.etlserver.registrator.v2.IDataSetRegistrationDetailsFactory;
+import ch.systemsx.cisd.imagereaders.IImageReader;
+import ch.systemsx.cisd.imagereaders.ImageID;
+import ch.systemsx.cisd.imagereaders.ImageReaderFactory;
+import ch.systemsx.cisd.openbis.common.io.FileBasedContentNode;
+import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageIdentifier;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageMetadata;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IntensityRange;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Location;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleOverviewImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformationBuffer;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
+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.DataSetType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingReadonlyQueryDAO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgAcquiredImageEnrichedDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgChannelDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgImageDatasetDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgImageTransformationDTO;
+
+/**
+ * Allows to prepare the image dataset which should be registered easily using the specified
+ * {@link SimpleImageDataConfig}.
+ * 
+ * @author Tomasz Pylak
+ */
+public class SimpleImageDataSetRegistrator
+{
+    public static final String OPTIMAL_DATASET_INTENSITY_RESCALING_DESCRIPTION =
+            "Optimal intensity rescaling for a series of images. "
+                    + "It allows to compare images of one plate's dataset to each other."
+                    + "At the same time it causes that the conversion to 8 bit color depth looses less information, "
+                    + "especially when images use only a small part of available intensities range.";
+
+    @Private
+    static interface IImageReaderFactory
+    {
+        IImageReader tryGetReader(String libraryName, String readerName);
+
+        IImageReader tryGetReaderForFile(String libraryName, String fileName);
+    }
+
+    private static class ImageTokensWithPath extends ImageMetadata
+    {
+        /** path relative to the incoming dataset directory */
+        private String imageRelativePath;
+
+        public ImageTokensWithPath(ImageMetadata imageTokens, String imageRelativePath)
+        {
+            setWell(imageTokens.getWell());
+            setChannelCode(imageTokens.getChannelCode());
+            setTileNumber(imageTokens.getTileNumber());
+            setDepth(imageTokens.tryGetDepth());
+            setTimepoint(imageTokens.tryGetTimepoint());
+            setSeriesNumber(imageTokens.tryGetSeriesNumber());
+            setImageIdentifier(imageTokens.tryGetImageIdentifier());
+            this.imageRelativePath = imageRelativePath;
+        }
+
+        public String getImagePath()
+        {
+            return imageRelativePath;
+        }
+    }
+
+    public static DataSetRegistrationDetails<ImageDataSetInformation> createImageDatasetDetails(
+            SimpleImageDataConfig simpleImageConfig, File incoming,
+            IDataSetRegistrationDetailsFactory<ImageDataSetInformation> factory)
+    {
+        return createImageDatasetDetails(simpleImageConfig, incoming, factory,
+                new IImageReaderFactory()
+                    {
+                        @Override
+                        public IImageReader tryGetReaderForFile(String libraryName, String fileName)
+                        {
+                            return ImageReaderFactory.tryGetReaderForFile(libraryName, fileName);
+                        }
+
+                        @Override
+                        public IImageReader tryGetReader(String libraryName, String readerName)
+                        {
+                            return ImageReaderFactory.tryGetReader(libraryName, readerName);
+                        }
+                    });
+    }
+
+    @Private
+    static DataSetRegistrationDetails<ImageDataSetInformation> createImageDatasetDetails(
+            SimpleImageDataConfig simpleImageConfig, File incoming,
+            IDataSetRegistrationDetailsFactory<ImageDataSetInformation> factory,
+            IImageReaderFactory readerFactory)
+    {
+        SimpleImageDataSetRegistrator registrator =
+                new SimpleImageDataSetRegistrator(simpleImageConfig, readerFactory);
+        return registrator.createImageDatasetDetails(incoming, factory);
+    }
+
+    final static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            SimpleImageDataSetRegistrator.class);
+
+    private final SimpleImageDataConfig simpleImageConfig;
+
+    private final IImageReaderFactory readerFactory;
+
+    private SimpleImageDataSetRegistrator(SimpleImageDataConfig simpleImageConfig,
+            IImageReaderFactory readerFactory)
+    {
+        this.simpleImageConfig = simpleImageConfig;
+        this.readerFactory = readerFactory;
+    }
+
+    private DataSetRegistrationDetails<ImageDataSetInformation> createImageDatasetDetails(
+            File incoming,
+            IDataSetRegistrationDetailsFactory<ImageDataSetInformation> imageDatasetFactory)
+    {
+        DataSetRegistrationDetails<ImageDataSetInformation> registrationDetails =
+                imageDatasetFactory.createDataSetRegistrationDetails();
+        ImageDataSetInformation imageDataset = registrationDetails.getDataSetInformation();
+
+        if (simpleImageConfig instanceof SimpleOverviewImageDataConfig)
+        {
+            SimpleOverviewImageDataConfig simpleOverviewImageConfig =
+                    (SimpleOverviewImageDataConfig) simpleImageConfig;
+
+            imageDataset.setContainerDatasetPermId(simpleOverviewImageConfig
+                    .getContainerDataSetCode());
+            imageDataset.setGenerateOverviewImagesFromRegisteredImages(simpleOverviewImageConfig
+                    .isGenerateOverviewImagesFromRegisteredImages());
+            imageDataset.setRegisterAsOverviewImageDataSet(true);
+        }
+
+        setImageDataset(incoming, imageDataset);
+        List<Channel> channels = simpleImageConfig.getChannels();
+        if (channels != null)
+        {
+            List<ChannelColorComponent> channelColorComponentsOrNull =
+                    simpleImageConfig.getChannelColorComponentsOrNull();
+            if (channelColorComponentsOrNull == null)
+            {
+                imageDataset.setChannels(channels);
+            } else
+            {
+                imageDataset.setChannels(channels, channelColorComponentsOrNull);
+            }
+        }
+
+        setRegistrationDetails(registrationDetails, imageDataset);
+        return registrationDetails;
+    }
+
+    /**
+     * Finds all images in the directory.
+     */
+    private List<File> listImageFiles(final File incoming)
+    {
+        String[] extensions = simpleImageConfig.getRecognizedImageExtensions();
+        if (incoming.isFile())
+        {
+            List<File> list = new ArrayList<File>();
+            if (extensionMatches(incoming, extensions))
+            {
+                list.add(incoming);
+            }
+            return list;
+        } else
+        {
+            return FileOperations.getInstance().listFiles(incoming, extensions, true);
+        }
+    }
+
+    private boolean extensionMatches(final File incoming, String[] extensions)
+    {
+        if (extensions == null || extensions.length == 0)
+        {
+            return true;
+        }
+        String fileExt = FilenameUtils.getExtension(incoming.getName());
+        if (fileExt == null)
+        {
+            fileExt = "";
+        }
+        for (String ext : extensions)
+        {
+            if (ext.equalsIgnoreCase(fileExt))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tokenizes file names of all images in the directory.
+     */
+    protected List<ImageTokensWithPath> parseImageTokens(List<File> imageFiles,
+            File incomingDirectory, IImageReader imageReaderOrNull)
+    {
+        List<ImageTokensWithPath> imageTokensList = new ArrayList<ImageTokensWithPath>();
+
+        for (File imageFile : imageFiles)
+        {
+            File file = new File(imageFile.getPath());
+            List<ImageIdentifier> identifiers = getImageIdentifiers(imageReaderOrNull, file);
+            String imageRelativePath = FileUtilities.getRelativeFilePath(incomingDirectory, file);
+            ImageMetadata[] imageTokens =
+                    simpleImageConfig.extractImagesMetadata(imageRelativePath, identifiers);
+            for (ImageMetadata imageToken : imageTokens)
+            {
+                imageToken.ensureValid(simpleImageConfig.isMicroscopyData());
+                imageTokensList.add(new ImageTokensWithPath(imageToken, imageRelativePath));
+            }
+        }
+        if (imageTokensList.isEmpty())
+        {
+            throw UserFailureException
+                    .fromTemplate(
+                            "No image tokens could be parsed from incoming directory '%s' for extensions %s!",
+                            incomingDirectory.getPath(),
+                            CollectionUtils.abbreviate(
+                                    simpleImageConfig.getRecognizedImageExtensions(), -1));
+        }
+        return imageTokensList;
+    }
+
+    private List<File> extractImageFiles(File incoming)
+    {
+        List<File> imageFiles = listImageFiles(incoming);
+        if (imageFiles.isEmpty())
+        {
+            throw UserFailureException.fromTemplate(
+                    "Incoming directory '%s' contains no images with extensions %s!", incoming
+                            .getPath(), CollectionUtils.abbreviate(
+                            simpleImageConfig.getRecognizedImageExtensions(), -1));
+        }
+        return imageFiles;
+    }
+
+    // this method can have a side effect - it autodetects the image reader if only the library is
+    // specified
+    private IImageReader tryCreateAndSaveImageReader(List<File> imageFiles)
+    {
+        IImageReader readerOrNull = null;
+        ImageLibraryInfo imageLibraryInfoOrNull = tryGetImageLibrary();
+        if (imageLibraryInfoOrNull != null)
+        {
+            readerOrNull = tryCreateImageReader(imageFiles, imageLibraryInfoOrNull);
+            if (readerOrNull != null)
+            {
+                // NOTE: ugly side effect which is used later on
+                // if (null == imageLibraryInfoOrNull.getReaderName())
+                // {
+                imageLibraryInfoOrNull.setReaderName(readerOrNull.getName());
+                // }
+            } else
+            {
+                throw ConfigurationFailureException.fromTemplate(
+                        "Cannot find any reader for '%s' library.", imageLibraryInfoOrNull);
+            }
+        }
+        return readerOrNull;
+    }
+
+    private IImageReader tryCreateImageReader(List<File> imageFiles,
+            ImageLibraryInfo imageLibraryInfo)
+    {
+        if (imageFiles.isEmpty())
+        {
+            return null;
+        }
+        File imageFile = imageFiles.get(0);
+        String libraryName = imageLibraryInfo.getName();
+        String readerNameOrNull = imageLibraryInfo.getReaderName();
+        if (readerNameOrNull != null)
+        {
+            return readerFactory.tryGetReader(libraryName, readerNameOrNull);
+        } else
+        {
+            return readerFactory.tryGetReaderForFile(libraryName, imageFile.getPath());
+        }
+    }
+
+    private ImageLibraryInfo tryGetImageLibrary()
+    {
+        return simpleImageConfig.getImageStorageConfiguration().tryGetImageLibrary();
+    }
+
+    private static List<ImageIdentifier> getImageIdentifiers(IImageReader readerOrNull,
+            File imageFile)
+    {
+        List<ImageIdentifier> ids = new ArrayList<ImageIdentifier>();
+        if (readerOrNull == null)
+        {
+            ids.add(ImageIdentifier.NULL);
+        } else
+        {
+            List<ImageID> imageIDs = readerOrNull.getImageIDs(imageFile);
+            for (ImageID imageID : imageIDs)
+            {
+                ids.add(new ImageIdentifier(imageID.getSeriesIndex(), imageID.getTimeSeriesIndex(),
+                        imageID.getFocalPlaneIndex(), imageID.getColorChannelIndex()));
+            }
+        }
+        Collections.sort(ids);
+        return ids;
+    }
+
+    /**
+     * Creates ImageFileInfo for a given path to an image.
+     */
+    protected ImageFileInfo createImageInfo(ImageTokensWithPath imageTokens, Geometry tileGeometry)
+    {
+        Location tileCoords =
+                simpleImageConfig.getTileCoordinates(imageTokens.getTileNumber(), tileGeometry);
+        ImageFileInfo img =
+                new ImageFileInfo(imageTokens.getChannelCode(), tileCoords.getRow(),
+                        tileCoords.getColumn(), imageTokens.getImagePath());
+        img.setTimepoint(imageTokens.tryGetTimepoint());
+        img.setDepth(imageTokens.tryGetDepth());
+        img.setSeriesNumber(imageTokens.tryGetSeriesNumber());
+        img.setWell(imageTokens.getWell());
+        img.setImageIdentifier(imageTokens.tryGetImageIdentifier());
+        return img;
+    }
+
+    /**
+     * @param imageTokensList list of ImageTokens for each image
+     * @param tileGeometry describes the matrix of tiles (aka fields or sides) in the well
+     */
+    protected List<ImageFileInfo> createImageInfos(List<ImageTokensWithPath> imageTokensList,
+            Geometry tileGeometry)
+    {
+        List<ImageFileInfo> images = new ArrayList<ImageFileInfo>();
+        for (ImageTokensWithPath imageTokens : imageTokensList)
+        {
+            ImageFileInfo image = createImageInfo(imageTokens, tileGeometry);
+            images.add(image);
+        }
+        return images;
+    }
+
+    private List<Channel> getAvailableChannels(List<ImageFileInfo> images)
+    {
+        Set<String> channelCodes = new LinkedHashSet<String>();
+        for (ImageFileInfo image : images)
+        {
+            channelCodes.add(image.getChannelCode());
+        }
+        List<Channel> channels = new ArrayList<Channel>();
+        for (String channelCode : channelCodes)
+        {
+            Channel channel = simpleImageConfig.createChannel(channelCode);
+            channels.add(channel);
+        }
+        return channels;
+    }
+
+    private static int getMaxTileNumber(List<ImageTokensWithPath> imageTokensList)
+    {
+        int max = 0;
+        for (ImageMetadata imageTokens : imageTokensList)
+        {
+            max = Math.max(max, imageTokens.getTileNumber());
+        }
+        return max;
+    }
+
+    // -------------------
+
+    private void computeAndAppendCommonFixedIntensityRangeTransformation(
+            List<ImageFileInfo> images, File incomingDir, List<Channel> channels,
+            IImageReader readerOrNull)
+    {
+        final List<Channel> channelsForComputation =
+                findChannelsToComputeFixedCommonIntensityRange(channels);
+        final Map<String, IntensityRange> map =
+                simpleImageConfig.getFixedIntensityRangeForAllImages();
+        final IntensityRange defaultLevelsOrNull = map.get(null);
+        for (Channel channel : channelsForComputation)
+        {
+            final IntensityRange levelsOrNull = map.get(channel.getCode());
+            final Levels intensityRange =
+                    levelsOrNull == null ? new Levels(defaultLevelsOrNull.getBlackPoint(),
+                            defaultLevelsOrNull.getWhitePoint()) : new Levels(
+                            levelsOrNull.getBlackPoint(), levelsOrNull.getWhitePoint());
+            operationLog.info(String.format(
+                    "Set intensity range for channel '%s' to fixed value: %s "
+                            + "(incoming directory '%s').", channel.getCode(),
+                    intensityRange.toString(), incomingDir.getName()));
+            appendCommonIntensityRangeTransformation(channel, intensityRange);
+        }
+    }
+
+    private List<Channel> findChannelsToComputeFixedCommonIntensityRange(List<Channel> channels)
+    {
+        final Map<String, ch.systemsx.cisd.openbis.dss.etl.dto.api.IntensityRange> map =
+                simpleImageConfig.getFixedIntensityRangeForAllImages();
+        final ch.systemsx.cisd.openbis.dss.etl.dto.api.IntensityRange defaultLevelOrNull =
+                map.get(null);
+        if (defaultLevelOrNull != null)
+        {
+            return channels;
+        }
+        final Set<String> channelCodesSet = map.keySet();
+        List<Channel> chosenChannels = new ArrayList<Channel>();
+        for (Channel channel : channels)
+        {
+            if (channelCodesSet.contains(channel.getCode()))
+            {
+                chosenChannels.add(channel);
+            }
+        }
+        return chosenChannels;
+    }
+
+    private void computeAndAppendCommonIntensityRangeTransformation(List<ImageFileInfo> images,
+            File incomingDir, List<Channel> channels, IImageReader readerOrNull)
+    {
+        final List<Channel> channelsForComputation =
+                tryFindChannelsToComputeCommonIntensityRange(channels);
+        if (channelsForComputation == null)
+        {
+            return;
+        }
+        for (Channel channel : channelsForComputation)
+        {
+            final String channelCode = channel.getCode();
+            final List<File> imagePaths = chooseChannelImages(images, incomingDir, channelCode);
+            operationLog.info(String.format("Computing intensity range for channel '%s'. "
+                    + "Found %d images for the channel in incoming directory '%s'.", channelCode,
+                    imagePaths.size(), incomingDir.getName()));
+            final Levels intensityRange;
+            intensityRange =
+                    tryComputeCommonIntensityRange(readerOrNull, imagePaths,
+                            simpleImageConfig.getComputeCommonIntensityRangeOfAllImagesThreshold());
+            if (intensityRange != null)
+            {
+                operationLog.info(String.format(
+                        "Computed intensity range for channel '%s': %s (incoming directory '%s').",
+                        channelCode, intensityRange.toString(), incomingDir.getName()));
+                appendCommonIntensityRangeTransformation(channel, intensityRange);
+            } else
+            {
+                operationLog
+                        .warn(String
+                                .format("Transformation cannot be generated for channel '%s' (incoming directory '%s').",
+                                        channelCode, incomingDir.getName()));
+            }
+        }
+    }
+
+    private void appendCommonIntensityRangeTransformation(Channel channel, Levels intensityRange)
+    {
+        ImageTransformationBuffer buffer = new ImageTransformationBuffer();
+        // append first
+        String label = simpleImageConfig.getComputeCommonIntensityRangeOfAllImagesLabel();
+        ImageTransformation imageTransformation =
+                buffer.appendRescaleGrayscaleIntensity(intensityRange.getMinLevel(),
+                        intensityRange.getMaxLevel(), label);
+        imageTransformation.setDescription(OPTIMAL_DATASET_INTENSITY_RESCALING_DESCRIPTION);
+        boolean isDefault = simpleImageConfig.isComputeCommonIntensityRangeOfAllImagesDefault();
+        imageTransformation.setDefault(isDefault);
+        buffer.appendAll(channel.getAvailableTransformations());
+
+        channel.setAvailableTransformations(buffer.getTransformations());
+    }
+
+    private static List<File> chooseChannelImages(List<ImageFileInfo> images, File incomingDir,
+            String channelCode)
+    {
+        String normalizedChannelCode = CodeNormalizer.normalize(channelCode);
+        List<File> channelImages = new ArrayList<File>();
+        for (ImageFileInfo imageFileInfo : images)
+        {
+            String imageChannelCode = CodeNormalizer.normalize(imageFileInfo.getChannelCode());
+            if (imageChannelCode.equals(normalizedChannelCode))
+            {
+                channelImages.add(new File(incomingDir, imageFileInfo.getImageRelativePath()));
+            }
+        }
+        return channelImages;
+    }
+
+    private List<Channel> tryFindChannelsToComputeCommonIntensityRange(List<Channel> channels)
+    {
+        List<String> channelCodes =
+                simpleImageConfig.getComputeCommonIntensityRangeOfAllImagesForChannels();
+        if (channelCodes == null)
+        {
+            return null;
+        }
+        if (channelCodes.isEmpty())
+        {
+            return channels;
+        }
+
+        Set<String> channelCodesSet = createNormalizedCodesSet(channelCodes);
+        List<Channel> chosenChannels = new ArrayList<Channel>();
+        for (Channel channel : channels)
+        {
+            if (channelCodesSet.contains(channel.getCode()))
+            {
+                chosenChannels.add(channel);
+            }
+        }
+        return chosenChannels;
+    }
+
+    private static Set<String> createNormalizedCodesSet(Collection<String> channelCodes)
+    {
+        final Set<String> normalizedCodes = new HashSet<String>();
+        for (String code : channelCodes)
+        {
+            normalizedCodes.add(CodeNormalizer.normalize(code));
+        }
+        return normalizedCodes;
+    }
+
+    /**
+     * Computes common intensity range for a list of files.
+     * 
+     * @return calculated levels or null if calculation couldn't succeed because some images where
+     *         not in gray scale
+     */
+    public static Levels tryComputeCommonIntensityRange(IImageReader readerOrNull,
+            List<File> imageFiles, float threshold)
+    {
+        String libraryName = (readerOrNull == null) ? null : readerOrNull.getLibraryName();
+        String readerName = (readerOrNull == null) ? null : readerOrNull.getName();
+        PixelHistogram histogram = new PixelHistogram();
+
+        for (File imageFile : imageFiles)
+        {
+            List<ImageIdentifier> imageIdentifiers = getImageIdentifiers(readerOrNull, imageFile);
+            for (ImageIdentifier imageIdentifier : imageIdentifiers)
+            {
+                BufferedImage image =
+                        loadUnchangedImage(imageFile, imageIdentifier, libraryName, readerName);
+                if (IntensityRescaling.isNotGrayscale(image))
+                {
+                    operationLog
+                            .warn(String
+                                    .format("Intensity range cannot be computed because image '%s' is not in grayscale.",
+                                            imageFile.getPath()));
+                    return null;
+                }
+                IntensityRescaling.addToLevelStats(histogram, image);
+            }
+        }
+        return IntensityRescaling.computeLevels(histogram, threshold);
+    }
+
+    private static BufferedImage loadUnchangedImage(File imageFile,
+            ImageIdentifier imageIdentifier, String libraryName, String readerName)
+    {
+        String imageStringIdentifier = imageIdentifier.getUniqueStringIdentifier();
+        return ImageUtil.loadUnchangedImage(new FileBasedContentNode(imageFile),
+                imageStringIdentifier, libraryName, readerName, null);
+    }
+
+    // -------------------
+    /**
+     * Extracts all images from the incoming directory.
+     * 
+     * @param incoming - folder with images
+     * @param dataset - here the result will be stored
+     */
+    protected void setImageDataset(File incoming, ImageDataSetInformation dataset)
+    {
+        dataset.setDatasetTypeCode(simpleImageConfig.getDataSetType());
+        dataset.setFileFormatCode(simpleImageConfig.getFileFormatType());
+        dataset.setMeasured(simpleImageConfig.isMeasuredData());
+
+        dataset.setSample(simpleImageConfig.getPlateSpace(), simpleImageConfig.getPlateCode());
+        dataset.setIncomingDirectory(incoming);
+
+        ImageDataSetStructure imageStruct = createImageDataSetStructure(incoming, dataset);
+        dataset.setImageDataSetStructure(imageStruct);
+    }
+
+    private ImageDataSetStructure createImageDataSetStructure(File incoming,
+            ImageDataSetInformation dataset)
+    {
+        List<ImageFileInfo> images = null;
+        List<Channel> channels = null;
+        Geometry tileGeometry = null;
+        if (dataset.isGenerateOverviewImagesFromRegisteredImages())
+        {
+            images = new ArrayList<ImageFileInfo>();
+            channels = new ArrayList<Channel>();
+            tileGeometry = extractImageFileInfos(dataset, images, channels);
+        } else
+        {
+            List<File> imageFiles = extractImageFiles(incoming);
+            IImageReader imageReaderOrNull = tryCreateAndSaveImageReader(imageFiles);
+            List<ImageTokensWithPath> imageTokensList =
+                    parseImageTokens(imageFiles, incoming, imageReaderOrNull);
+
+            int maxTileNumber = getMaxTileNumber(imageTokensList);
+            tileGeometry = simpleImageConfig.getTileGeometry(imageTokensList, maxTileNumber);
+
+            images = createImageInfos(imageTokensList, tileGeometry);
+            channels = getAvailableChannels(images);
+
+            if (simpleImageConfig.isFixedIntensityRangeForAllImagesDefined())
+            {
+                computeAndAppendCommonFixedIntensityRangeTransformation(images, incoming, channels,
+                        imageReaderOrNull);
+            } else
+            {
+                computeAndAppendCommonIntensityRangeTransformation(images, incoming, channels,
+                        imageReaderOrNull);
+            }
+        }
+
+        ImageDataSetStructure imageStruct = new ImageDataSetStructure();
+        imageStruct.setImages(images);
+        imageStruct.setChannels(channels);
+        imageStruct.setTileGeometry(tileGeometry.getNumberOfRows(),
+                tileGeometry.getNumberOfColumns());
+
+        imageStruct.setImageStorageConfiguraton(simpleImageConfig.getImageStorageConfiguration());
+        return imageStruct;
+    }
+
+    private Geometry extractImageFileInfos(DataSetInformation dataset, List<ImageFileInfo> images,
+            List<Channel> channels)
+    {
+        IImagingReadonlyQueryDAO query = DssScreeningUtils.getQuery();
+
+        List<ImgImageDatasetDTO> containers =
+                DssScreeningUtils.getQuery().listImageDatasetsByPermId(
+                        dataset.tryGetContainerDatasetPermId());
+
+        for (ImgImageDatasetDTO container : containers)
+        {
+            List<ImgAcquiredImageEnrichedDTO> acquiredImages =
+                    query.listAllEnrichedAcquiredImagesForDataSet(container.getId());
+            for (ImgAcquiredImageEnrichedDTO acquiredImage : acquiredImages)
+            {
+                images.add(createImageFileInfo(container, acquiredImage));
+            }
+
+            List<ImgChannelDTO> channelDTOs = query.getChannelsByDatasetId(container.getId());
+            for (ImgChannelDTO channelDTO : channelDTOs)
+            {
+                Channel channel = createChannel(query, channelDTO);
+
+                channels.add(channel);
+            }
+
+            return Geometry.createFromRowColDimensions(container.getFieldNumberOfRows(),
+                    container.getFieldNumberOfColumns());
+        }
+
+        return null;
+    }
+
+    private Channel createChannel(IImagingReadonlyQueryDAO query, ImgChannelDTO channelDTO)
+    {
+        Channel channel =
+                new Channel(channelDTO.getCode(), channelDTO.getLabel(), new ChannelColorRGB(
+                        channelDTO.getRedColorComponent(), channelDTO.getGreenColorComponent(),
+                        channelDTO.getBlueColorComponent()));
+        channel.setDescription(channelDTO.getDescription());
+        channel.setWavelength(channelDTO.getWavelength());
+
+        List<ImgImageTransformationDTO> transformationDTOs =
+                query.listImageTransformations(channelDTO.getId());
+        ImageTransformation[] transformations = new ImageTransformation[transformationDTOs.size()];
+        int counter = 0;
+        for (ImgImageTransformationDTO transformationDTO : transformationDTOs)
+        {
+            ImageTransformation transformation =
+                    new ImageTransformation(transformationDTO.getCode(),
+                            transformationDTO.getLabel(), transformationDTO.getDescription(),
+                            transformationDTO.getImageTransformerFactory());
+            transformations[counter++] = transformation;
+        }
+        channel.setAvailableTransformations(transformations);
+
+        return channel;
+    }
+
+    private ImageFileInfo createImageFileInfo(ImgImageDatasetDTO container,
+            ImgAcquiredImageEnrichedDTO acquiredImage)
+    {
+        ImageFileInfo img =
+                new ImageFileInfo(acquiredImage.getChannelCode(), acquiredImage.getTileRow(),
+                        acquiredImage.getTileColumn(), acquiredImage.getImageFilePath());
+        img.setTimepoint(acquiredImage.getT());
+        img.setDepth(acquiredImage.getZ());
+        img.setSeriesNumber(acquiredImage.getSeriesNumber());
+
+        if (acquiredImage.getSpotRow() != null && acquiredImage.getSpotColumn() != null)
+        {
+            img.setWell(acquiredImage.getSpotRow(), acquiredImage.getSpotColumn());
+        }
+        img.setUniqueImageIdentifier(acquiredImage.getImageIdOrNull());
+        img.setContainerDataSetCode(container.getPermId());
+
+        return img;
+    }
+
+    private <T extends DataSetInformation> void setRegistrationDetails(
+            DataSetRegistrationDetails<T> registrationDetails, T dataset)
+    {
+        registrationDetails.setDataSetInformation(dataset);
+        registrationDetails.setFileFormatType(new FileFormatType(simpleImageConfig
+                .getFileFormatType()));
+        registrationDetails.setDataSetType(new DataSetType(simpleImageConfig.getDataSetType()));
+        registrationDetails.setMeasuredData(simpleImageConfig.isMeasuredData());
+
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java
index f8dcf80438f4a7c533188bb834396409b56c114d..e1b839ff3e4b4b7c045ba01d236992906662e51f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java
@@ -44,7 +44,7 @@ import ch.systemsx.cisd.openbis.dss.etl.IImagingDatasetLoader;
 import ch.systemsx.cisd.openbis.dss.etl.IImagingLoaderStrategy;
 import ch.systemsx.cisd.openbis.dss.etl.ImagingLoaderStrategyFactory;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageTransfomationFactories;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
 import ch.systemsx.cisd.openbis.dss.generic.server.ResponseContentStream;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.DatasetAcquiredImagesReference;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageChannelStackReference;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/jython/ScreeningJythonIngestionService.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/jython/ScreeningJythonIngestionService.java
index bc481d0ced2f016c9eb91b205c2be94ba3739978..0a9572465444efcd6ed03c09b65e2d10c5f81888 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/jython/ScreeningJythonIngestionService.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/jython/ScreeningJythonIngestionService.java
@@ -21,16 +21,15 @@ import java.util.Properties;
 
 import ch.systemsx.cisd.common.action.IDelegatedActionWithResult;
 import ch.systemsx.cisd.etlserver.registrator.DataSetFile;
-import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSetRegistrationTransaction;
-import ch.systemsx.cisd.etlserver.registrator.recovery.AutoRecoverySettings;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSetRegistrationTransaction;
 import ch.systemsx.cisd.etlserver.registrator.v2.AbstractOmniscientTopLevelDataSetRegistrator.NoOpDelegate;
 import ch.systemsx.cisd.etlserver.registrator.v2.DataSetRegistrationService;
 import ch.systemsx.cisd.etlserver.registrator.v2.IDataSetRegistrationDetailsFactory;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IImagingDataSetRegistrationTransactionV2;
-import ch.systemsx.cisd.openbis.dss.etl.jython.ImagingDataSetRegistrationTransaction;
-import ch.systemsx.cisd.openbis.dss.etl.jython.JythonPlateDataSetHandlerUtils;
-import ch.systemsx.cisd.openbis.dss.etl.jython.JythonPlateDatasetFactory;
+import ch.systemsx.cisd.openbis.dss.etl.jython.v2.ImagingDataSetRegistrationTransaction;
 import ch.systemsx.cisd.openbis.dss.etl.jython.v2.ImagingDataSetRegistrationTransactionV2Delegate;
+import ch.systemsx.cisd.openbis.dss.etl.jython.v2.JythonPlateDataSetHandlerUtils;
+import ch.systemsx.cisd.openbis.dss.etl.jython.v2.JythonPlateDatasetFactory;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.jython.IPluginScriptRunnerFactory;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.jython.JythonIngestionService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
@@ -85,8 +84,7 @@ public class ScreeningJythonIngestionService extends JythonIngestionService
                             return new ImagingDataSetRegistrationTransaction(
                                     rollBackStackParentFolder, workingDirectory, stagingDirectory,
                                     this, factory,
-                                    JythonPlateDataSetHandlerUtils.parseOriginalDir(properties),
-                                    AutoRecoverySettings.DO_NOT_USE_AUTO_RECOVERY);
+                                    JythonPlateDataSetHandlerUtils.parseOriginalDir(properties));
                         }
                     };
         return service;
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/ImagingChannelsCreatorTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/ImagingChannelsCreatorTest.java
index 56d2af34acc16f8836be81428ca1bb6f445e0b24..f36578d6ee2794ce36f6b8eec7288a3a80deb7b5 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/ImagingChannelsCreatorTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/ImagingChannelsCreatorTest.java
@@ -24,9 +24,9 @@ import org.testng.annotations.Test;
 
 import ch.rinn.restrictions.Friend;
 import ch.systemsx.cisd.openbis.dss.etl.ImagingDatabaseHelper.ImagingChannelsCreator;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColor;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
 
 /**
  * Test of {@link ImagingChannelsCreator}
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/TileGeometryOracleTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/TileGeometryOracleTest.java
index dce9f3dc262629200b9f46b120cdb16b5c2195f8..04b3f36289338c0b3d64f227c88003de24c22d60 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/TileGeometryOracleTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/TileGeometryOracleTest.java
@@ -23,7 +23,7 @@ import org.testng.AssertJUnit;
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.common.geometry.SpatialPoint;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Location;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Location;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
 
 /**
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ImageMetadataExtractorTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ImageMetadataExtractorTest.java
index fa199d9329e8d34d6f86b86fbb6618191941122e..b3db6c9f92cd08666167e338cc23ab4c265a919e 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ImageMetadataExtractorTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ImageMetadataExtractorTest.java
@@ -29,7 +29,7 @@ import org.testng.annotations.Test;
 
 import com.csvreader.CsvReader;
 
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Location;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Location;
 
 /**
  * @author Kaloyan Enimanev
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ChannelColorTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ChannelColorTest.java
index 9f14f9af3b0a3748c5b107cb9ad7941f51e35b8c..a1da1f2eeee26b70c229497d7a2263c25492b5d9 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ChannelColorTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ChannelColorTest.java
@@ -23,7 +23,7 @@ import org.testng.AssertJUnit;
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.common.test.AssertionUtil;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColor;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ImageChannelColor;
 
 /**
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingQueryDAOTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingQueryDAOTest.java
index 68400f219919c41ed89bce0a50fd2e3dd06b63e1..f6e928b8217152bedfdb6a4ede5715a7f40939bf 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingQueryDAOTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingQueryDAOTest.java
@@ -33,7 +33,7 @@ import org.testng.annotations.Test;
 import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.common.test.AssertionUtil;
 import ch.systemsx.cisd.hcs.Location;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
 import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
 import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ExampleImageTransformerFactory;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.AbstractDBTest;
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorComponentTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorComponentTest.java
similarity index 91%
rename from screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorComponentTest.java
rename to screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorComponentTest.java
index 963cb1aeb944f62388beee52dfb8b0d36c8c53ba..7385de4f751d2298280822cd16f869c37d72976a 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColorComponentTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/ChannelColorComponentTest.java
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
 
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
 
 /**
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformerTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformerTest.java
similarity index 93%
rename from screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformerTest.java
rename to screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformerTest.java
index 070d7de5ec82a56449ac325df7db1d5e1856becb..ecb3efca5bbae3eae841a9153283a6461f19bab5 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ConvertToolImageTransformerTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ConvertToolImageTransformerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations;
 
 import java.awt.image.BufferedImage;
 import java.io.File;
@@ -23,6 +23,7 @@ import org.testng.AssertJUnit;
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.base.image.IImageTransformer;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ConvertToolImageTransformerFactory;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtilTest;
 
 /**
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBufferTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformationBufferTest.java
similarity index 89%
rename from screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBufferTest.java
rename to screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformationBufferTest.java
index f0acbf746fa547850d87d4431a9aecf311869477..25ffe09e40151eda924d32a28a8b1aaa9497632c 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBufferTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/transformations/ImageTransformationBufferTest.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations;
 
 import org.testng.AssertJUnit;
 import org.testng.annotations.Test;
 
 import ch.rinn.restrictions.Friend;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.ImageTransformationBuffer;
 
 /**
  * Test of {@link ImageTransformationBuffer}
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/FeatureVectorContainerDataSetTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/FeatureVectorContainerDataSetTest.java
similarity index 92%
rename from screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/FeatureVectorContainerDataSetTest.java
rename to screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/FeatureVectorContainerDataSetTest.java
index ad86354329499324b0ae667cf8a58030d6954589..cc91242711051faa0d03e78c676234b7357ce38b 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/FeatureVectorContainerDataSetTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/FeatureVectorContainerDataSetTest.java
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorContainerDataSet;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.impl.FeatureVectorContainerDataSet;
 
 /**
  * @author Jakub Straszewski
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistratorTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/SimpleImageDataSetRegistratorTest.java
similarity index 96%
rename from screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistratorTest.java
rename to screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/SimpleImageDataSetRegistratorTest.java
index 218bcaaa4f95bd3a3d0781458956637a4344dbd9..334fac275d8e3d9a6138dba0337ce078d9e9ae75 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistratorTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/jython/v1/SimpleImageDataSetRegistratorTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.etl.jython;
+package ch.systemsx.cisd.openbis.dss.etl.jython.v1;
 
 import java.io.File;
 import java.util.Arrays;
@@ -33,13 +33,13 @@ import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.v1.IDataSetRegistrationDetailsFactory;
 import ch.systemsx.cisd.imagereaders.IImageReader;
 import ch.systemsx.cisd.imagereaders.ImageID;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColor;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageContainerDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColor;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageContainerDataConfig;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.IntensityRangeImageTransformerFactory;
-import ch.systemsx.cisd.openbis.dss.etl.jython.SimpleImageDataSetRegistrator.IImageReaderFactory;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations.IntensityRangeImageTransformerFactory;
+import ch.systemsx.cisd.openbis.dss.etl.jython.v1.SimpleImageDataSetRegistrator.IImageReaderFactory;
 
 /**
  * @author Franz-Josef Elmer
@@ -252,8 +252,7 @@ public class SimpleImageDataSetRegistratorTest extends AbstractFileSystemTestCas
         configData.setImageLibrary("MyLibrary");
         assertFalse(configData.isFixedIntensityRangeForAllImagesDefined());
         configData.setDefaultFixedIntensityRangeForAllImages(99, 1001);
-        configData.addFixedIntensityRangeForAllImages("channel-4", 51,
-                1017);
+        configData.addFixedIntensityRangeForAllImages("channel-4", 51, 1017);
         assertTrue(configData.isFixedIntensityRangeForAllImagesDefined());
         DataSetRegistrationDetails<ImageDataSetInformation> actualDetails =
                 SimpleImageDataSetRegistrator.createImageDatasetDetails(configData, incoming,
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java
index 59837cb8769828d332be3b18f486ceb60e4131d9..ceac2fb6ed1281fd3d4483b6d0375af8deb60e68 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java
@@ -46,7 +46,7 @@ import ch.systemsx.cisd.openbis.dss.etl.AbsoluteImageReference;
 import ch.systemsx.cisd.openbis.dss.etl.IImagingDatasetLoader;
 import ch.systemsx.cisd.openbis.dss.etl.ImagingLoaderStrategyFactory;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageTransfomationFactories;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.DatasetAcquiredImagesReference;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageChannelStackReference;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageTransformationParams;
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 cbc2f8a27ac41fd13e0ff36a4b1088a30984613d..580e746d64afca3a7ac9bdd24b421c964b87100e 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
@@ -55,7 +55,7 @@ import ch.systemsx.cisd.hcs.Location;
 import ch.systemsx.cisd.openbis.dss.etl.AbsoluteImageReference;
 import ch.systemsx.cisd.openbis.dss.etl.IImagingDatasetLoader;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageTransfomationFactories;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
 import ch.systemsx.cisd.openbis.dss.generic.server.DatasetSessionAuthorizer;
 import ch.systemsx.cisd.openbis.dss.generic.server.DssServiceRpcAuthorizationAdvisor;
 import ch.systemsx.cisd.openbis.dss.generic.server.DssServiceRpcAuthorizationAdvisor.DssServiceRpcAuthorizationMethodInterceptor;
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/jython/ScreeningJythonBasedAggregationServiceReportingPluginTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/jython/ScreeningJythonBasedAggregationServiceReportingPluginTest.java
index eea0a932da28e6df424f89b06615f3d94bc35572..fa39be1827a104d1fc98cac46de3a87a4a948136 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/jython/ScreeningJythonBasedAggregationServiceReportingPluginTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/jython/ScreeningJythonBasedAggregationServiceReportingPluginTest.java
@@ -32,9 +32,9 @@ import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.jython.JythonBasedAggregationServiceReportingPluginTest.ParametersBuilder;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IReportingPluginTask;
 import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IDataSourceQueryService;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.ISearchService;
-import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.authorization.IAuthorizationService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.IDataSourceQueryService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISearchService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.authorization.IAuthorizationService;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
 import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.IScreeningOpenbisServiceFacade;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ExperimentIdentifier;