From 5a538377922b3e7ad72483c5885882593687129b Mon Sep 17 00:00:00 2001
From: izabel <izabel>
Date: Mon, 23 Aug 2010 11:17:23 +0000
Subject: [PATCH] [LMS-1708] Codes and labels for channels

SVN: 17575
---
 .../etl/AbstractHCSImageFileExtractor.java    |  37 +++---
 .../openbis/dss/etl/AcquiredPlateImage.java   |  10 +-
 .../openbis/dss/etl/ChannelDescription.java   |  61 +++++++++
 .../openbis/dss/etl/HCSDatasetUploader.java   |  14 +-
 .../openbis/dss/etl/HCSImageCheckList.java    |  22 ++--
 .../dss/etl/HCSImageFileExtractionResult.java |  24 +++-
 .../dss/etl/HCSImageFileExtractor.java        |  31 ++---
 .../dss/etl/IHCSImageDatasetLoader.java       |   4 +-
 .../dss/etl/PlateStorageProcessor.java        | 120 +++++++++++++++---
 .../ScreeningContainerDatasetInfoHelper.java  |  20 +--
 .../etl/dataaccess/HCSImageDatasetLoader.java |  10 +-
 .../etl/dynamix/HCSImageFileExtractor.java    |  13 +-
 .../server/MergingImagesDownloadServlet.java  |   4 +-
 .../server/images/ImageChannelsUtils.java     |  10 +-
 .../server/DssServiceRpcScreening.java        |   8 +-
 .../detailviewers/ChannelComboBox.java        |  10 +-
 .../detailviewers/PlateMaterialReviewer.java  |   2 +-
 .../detailviewers/WellContentDialog.java      |   6 +-
 .../application/detailviewers/WellImages.java |   4 +-
 .../api/v1/dto/ImageDatasetMetadata.java      |   2 +-
 .../api/v1/dto/PlateImageReference.java       |   2 +-
 .../basic/dto/PlateImageParameters.java       |  12 +-
 .../shared/imaging/HCSDatasetLoader.java      |  18 +--
 .../imaging/dataaccess/IImagingQueryDAO.java  |  12 +-
 .../imaging/dataaccess/ImgChannelDTO.java     |  43 +++++--
 .../dataaccess/ImagingQueryDAOTest.java       |  10 +-
 26 files changed, 336 insertions(+), 173 deletions(-)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ChannelDescription.java

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractHCSImageFileExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractHCSImageFileExtractor.java
index a436a0a0456..e5f4dad6741 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractHCSImageFileExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractHCSImageFileExtractor.java
@@ -299,29 +299,36 @@ abstract public class AbstractHCSImageFileExtractor implements IHCSImageFileExtr
         return components;
     }
 
-    protected final static List<String> extractChannelNames(final Properties properties)
-    {
-        return PropertyUtils.getMandatoryList(properties, PlateStorageProcessor.CHANNEL_NAMES);
-    }
-
-    protected final static Set<Channel> createChannels(List<String> channelNames)
+    protected final static Set<Channel> createChannels(List<ChannelDescription> channelDescriptions)
     {
         Set<Channel> channels = new HashSet<Channel>();
-        for (String channelName : channelNames)
+        for (ChannelDescription channelDescription : channelDescriptions)
         {
-            channels.add(new Channel(channelName, null, null));
+            channels.add(new Channel(channelDescription.getCode(), null, null, channelDescription
+                    .getLabel()));
         }
         return channels;
     }
 
-    protected final static void ensureChannelExist(List<String> channelNames, String channelName)
+    protected final static List<ChannelDescription> tryExtractChannelDescriptions(
+            final Properties properties)
+    {
+        return PlateStorageProcessor.extractChannelDescriptions(properties);
+    }
+
+    protected final static void ensureChannelExist(List<ChannelDescription> channelDescriptions,
+            String channelCode)
     {
-        if (channelNames.indexOf(channelName) == -1)
+        for (ChannelDescription channelDescription : channelDescriptions)
         {
-            throw UserFailureException.fromTemplate(
-                    "Channel '%s' is not one of: %s. Change the configuration.", channelName,
-                    channelNames);
+            if (channelDescription.getCode().equals(channelCode))
+            {
+                return;
+            }
         }
+        throw UserFailureException.fromTemplate(
+                "Channel '%s' is not one of: %s. Change the configuration.", channelCode,
+                channelDescriptions);
     }
 
     protected final static Geometry getWellGeometry(final Properties properties)
@@ -342,10 +349,10 @@ abstract public class AbstractHCSImageFileExtractor implements IHCSImageFileExtr
     }
 
     protected static final AcquiredPlateImage createImage(Location plateLocation,
-            Location wellLocation, String imageRelativePath, String channelName,
+            Location wellLocation, String imageRelativePath, String channelCode,
             Float timepointOrNull, ColorComponent colorComponent)
     {
-        return new AcquiredPlateImage(plateLocation, wellLocation, channelName, timepointOrNull,
+        return new AcquiredPlateImage(plateLocation, wellLocation, channelCode, timepointOrNull,
                 null, new RelativeImageReference(imageRelativePath, null, colorComponent));
     }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AcquiredPlateImage.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AcquiredPlateImage.java
index b505fb4fd4e..b5612d067d1 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AcquiredPlateImage.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AcquiredPlateImage.java
@@ -30,7 +30,7 @@ public class AcquiredPlateImage extends AbstractHashable
 
     private final Location tileLocation;
 
-    private final String channelName;
+    private final String channelCode;
 
     // can be null
     private final Float timePointOrNull, depthOrNull;
@@ -40,12 +40,12 @@ public class AcquiredPlateImage extends AbstractHashable
 
     private RelativeImageReference thumbnailFilePathOrNull;
     
-    public AcquiredPlateImage(Location wellLocation, Location tileLocation, String channelName,
+    public AcquiredPlateImage(Location wellLocation, Location tileLocation, String channelCode,
             Float timePointOrNull, Float depthOrNull, RelativeImageReference imageFilePath)
     {
         this.wellLocation = wellLocation;
         this.tileLocation = tileLocation;
-        this.channelName = channelName.toUpperCase();
+        this.channelCode = channelCode.toUpperCase();
         this.timePointOrNull = timePointOrNull;
         this.depthOrNull = depthOrNull;
         this.imageFilePath = imageFilePath;
@@ -71,9 +71,9 @@ public class AcquiredPlateImage extends AbstractHashable
         return tileLocation.getX();
     }
 
-    public String getChannelName()
+    public String getChannelCode()
     {
-        return channelName;
+        return channelCode;
     }
 
     public Float tryGetTimePoint()
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ChannelDescription.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ChannelDescription.java
new file mode 100644
index 00000000000..2596bee8eb1
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ChannelDescription.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl;
+
+/**
+ * @author Izabela Adamczyk
+ */
+public class ChannelDescription
+{
+
+    private final String code;
+
+    private final String label;
+
+    public ChannelDescription(String name)
+    {
+        assert name != null;
+        this.code = normalize(name);
+        this.label = name;
+    }
+
+    private String normalize(String name)
+    {
+        if (name == null)
+        {
+            return null;
+        }
+        return name.toUpperCase().replaceAll("[^A-Z0-9]", "_");
+    }
+
+    public ChannelDescription(String code, String label)
+    {
+        assert code != null && label != null;
+        this.code = code;
+        this.label = label;
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public String getLabel()
+    {
+        return label;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSDatasetUploader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSDatasetUploader.java
index da3e65569ab..a38c34bc0b7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSDatasetUploader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSDatasetUploader.java
@@ -65,23 +65,23 @@ public class HCSDatasetUploader
 
     private static class AcquiredImageInStack
     {
-        private final String channelName;
+        private final String channelCode;
 
         private final RelativeImageReference imageFilePath;
 
         private final RelativeImageReference thumbnailPathOrNull;
 
-        public AcquiredImageInStack(String channelName, RelativeImageReference imageFilePath,
+        public AcquiredImageInStack(String channelCode, RelativeImageReference imageFilePath,
                 RelativeImageReference thumbnailPathOrNull)
         {
-            this.channelName = channelName.toUpperCase();
+            this.channelCode = channelCode.toUpperCase();
             this.imageFilePath = imageFilePath;
             this.thumbnailPathOrNull = thumbnailPathOrNull;
         }
 
-        public String getChannelName()
+        public String getChannelCode()
         {
-            return channelName;
+            return channelCode;
         }
 
         public RelativeImageReference getImageFilePath()
@@ -134,7 +134,7 @@ public class HCSDatasetUploader
 
     private static AcquiredImageInStack makeAcquiredImageInStack(AcquiredPlateImage image)
     {
-        return new AcquiredImageInStack(image.getChannelName(), image.getImageReference(), image
+        return new AcquiredImageInStack(image.getChannelCode(), image.getImageReference(), image
                 .getThumbnailFilePathOrNull());
     }
 
@@ -184,7 +184,7 @@ public class HCSDatasetUploader
         List<ImgAcquiredImageDTO> acquiredImageDTOs = imagesToCreate.getAcquiredImages();
         for (AcquiredImageInStack image : images)
         {
-            long channelTechId = channelsMap.get(image.getChannelName());
+            long channelTechId = channelsMap.get(image.getChannelCode());
 
             ImgImageDTO imageDTO = mkImageWithIdDTO(image.getImageFilePath());
             ImgImageDTO thumbnailDTO = tryMkImageWithIdDTO(image.getThumbnailPathOrNull());
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageCheckList.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageCheckList.java
index 73fa86b240c..e03a7b1337d 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageCheckList.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageCheckList.java
@@ -39,10 +39,10 @@ public final class HCSImageCheckList
 
     private final Map<FullLocation, Check> imageMap;
 
-    public HCSImageCheckList(final List<String> channelNames, final PlateDimension plateGeometry,
+    public HCSImageCheckList(final List<String> channelCodes, final PlateDimension plateGeometry,
             final Geometry wellGeometry)
     {
-        if (channelNames.size() < 1)
+        if (channelCodes.size() < 1)
         {
             throw new IllegalArgumentException("Number of channels smaller than one.");
         }
@@ -55,7 +55,7 @@ public final class HCSImageCheckList
             throw new IllegalArgumentException("Unspecified well geometry.");
         }
         imageMap = new HashMap<FullLocation, Check>();
-        for (String channelName : channelNames)
+        for (String channelCode : channelCodes)
         {
             for (int wellCol = 1; wellCol <= plateGeometry.getColsNum(); wellCol++)
             {
@@ -66,13 +66,13 @@ public final class HCSImageCheckList
                         for (int tileRow = 1; tileRow <= wellGeometry.getRows(); tileRow++)
                         {
                             imageMap.put(new FullLocation(wellRow, wellCol, tileRow, tileCol,
-                                    channelName), new Check());
+                                    channelCode), new Check());
                         }
                     }
                 }
             }
         }
-        assert imageMap.size() == channelNames.size() * plateGeometry.getColsNum()
+        assert imageMap.size() == channelCodes.size() * plateGeometry.getColsNum()
                 * plateGeometry.getRowsNum() * wellGeometry.getColumns() * wellGeometry.getRows() : "Wrong map size";
     }
 
@@ -95,7 +95,7 @@ public final class HCSImageCheckList
     private static FullLocation createLocation(AcquiredPlateImage image)
     {
         return new FullLocation(image.getWellRow(), image.getWellColumn(), image.getTileRow(),
-                image.getTileColumn(), image.getChannelName());
+                image.getTileColumn(), image.getChannelCode());
     }
 
     public final List<FullLocation> getCheckedOnFullLocations()
@@ -119,7 +119,7 @@ public final class HCSImageCheckList
     {
         private boolean checkedOff;
 
-        private List<Float> timepoints = new ArrayList<Float>();
+        private final List<Float> timepoints = new ArrayList<Float>();
 
         final void checkOff(Float timepointOrNull)
         {
@@ -139,15 +139,15 @@ public final class HCSImageCheckList
 
         final int tileRow, tileCol;
 
-        final String channelName;
+        final String channelCode;
 
-        public FullLocation(int wellRow, int wellCol, int tileRow, int tileCol, String channelName)
+        public FullLocation(int wellRow, int wellCol, int tileRow, int tileCol, String channelCode)
         {
             this.wellRow = wellRow;
             this.wellCol = wellCol;
             this.tileRow = tileRow;
             this.tileCol = tileCol;
-            this.channelName = channelName.toUpperCase();
+            this.channelCode = channelCode.toUpperCase();
         }
 
         private final static String toString(final int row, final int col, final String type)
@@ -162,7 +162,7 @@ public final class HCSImageCheckList
         @Override
         public final String toString()
         {
-            return "[channel=" + channelName + ", " + toString(wellRow, wellCol, "well") + ", "
+            return "[channel=" + channelCode + ", " + toString(wellRow, wellCol, "well") + ", "
                     + toString(tileRow, tileCol, "tile") + "]";
         }
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageFileExtractionResult.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageFileExtractionResult.java
index 5144c71ff54..2c2f5f365c7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageFileExtractionResult.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageFileExtractionResult.java
@@ -60,7 +60,7 @@ public final class HCSImageFileExtractionResult
     /**
      * A channel in which the image has been acquired.
      * <p>
-     * Each channel has its <code>name</code> which uniquely identifies it in one experiment or
+     * Each channel has its <code>code</code> which uniquely identifies it in one experiment or
      * dataset.
      * </p>
      * 
@@ -68,23 +68,27 @@ public final class HCSImageFileExtractionResult
      */
     public static final class Channel
     {
-        private final String name;
+        private final String code;
+
+        private final String label;
 
         private final String description;
 
         private final Integer wavelength;
 
-        public Channel(String name, String descriptionOrNull, Integer wavelengthOrNull)
+        public Channel(String code, String descriptionOrNull, Integer wavelengthOrNull, String label)
         {
-            assert name != null : "name is null";
-            this.name = name;
+            assert code != null : "code is null";
+            assert label != null : "label is null";
+            this.label = label;
+            this.code = code;
             this.description = descriptionOrNull;
             this.wavelength = wavelengthOrNull;
         }
 
-        public String getName()
+        public String getCode()
         {
-            return name;
+            return code;
         }
 
         public String tryGetDescription()
@@ -96,6 +100,12 @@ public final class HCSImageFileExtractionResult
         {
             return wavelength;
         }
+
+        public String getLabel()
+        {
+            return label;
+        }
+
     }
 
 }
\ No newline at end of file
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 2fa55ea0b2b..b21a5aa7689 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,6 @@ import java.util.Set;
 import ch.systemsx.cisd.bds.hcs.Geometry;
 import ch.systemsx.cisd.bds.hcs.Location;
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
-import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.dss.etl.HCSImageFileExtractionResult.Channel;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
@@ -50,7 +49,7 @@ public class HCSImageFileExtractor extends AbstractHCSImageFileExtractor
 
     private final TileMapper tileMapperOrNull;
 
-    private final List<String> channelNames;
+    private final List<ChannelDescription> channelDescriptions;
 
     private final List<ColorComponent> channelColorComponentsOrNull;
 
@@ -59,7 +58,7 @@ public class HCSImageFileExtractor extends AbstractHCSImageFileExtractor
     public HCSImageFileExtractor(final Properties properties)
     {
         super(properties);
-        this.channelNames = extractChannelNames(properties);
+        this.channelDescriptions = tryExtractChannelDescriptions(properties);
         this.channelColorComponentsOrNull = tryGetChannelComponents(properties);
         checkChannelsAndColorComponents();
         this.wellGeometry = getWellGeometry(properties);
@@ -70,7 +69,7 @@ public class HCSImageFileExtractor extends AbstractHCSImageFileExtractor
     private void checkChannelsAndColorComponents()
     {
         if (channelColorComponentsOrNull != null
-                && channelColorComponentsOrNull.size() != channelNames.size())
+                && channelColorComponentsOrNull.size() != channelDescriptions.size())
         {
             throw ConfigurationFailureException.fromTemplate(
                     "There should be exactly one color component for each channel name."
@@ -126,34 +125,24 @@ public class HCSImageFileExtractor extends AbstractHCSImageFileExtractor
             for (int i = 0; i < channelColorComponentsOrNull.size(); i++)
             {
                 ColorComponent colorComponent = channelColorComponentsOrNull.get(i);
-                String channelName = channelNames.get(i);
-                images.add(createImage(plateLocation, wellLocation, imageRelativePath, channelName,
-                        timepointOrNull, colorComponent));
+                ChannelDescription channelDescription = channelDescriptions.get(i);
+                images.add(createImage(plateLocation, wellLocation, imageRelativePath,
+                        channelDescription.getCode(), timepointOrNull, colorComponent));
             }
         } else
         {
-            String channelName = channelToken.toUpperCase();
-            ensureChannelExist(channelName);
-            images.add(createImage(plateLocation, wellLocation, imageRelativePath, channelName,
+            String channelCode = channelToken.toUpperCase();
+            ensureChannelExist(channelDescriptions, channelCode);
+            images.add(createImage(plateLocation, wellLocation, imageRelativePath, channelCode,
                     timepointOrNull, null));
         }
         return images;
     }
 
-    private void ensureChannelExist(String channelName)
-    {
-        if (channelNames.indexOf(channelName) == -1)
-        {
-            throw UserFailureException.fromTemplate(
-                    "Channel '%s' is not one of: %s. Change the configuration.", channelName,
-                    channelNames);
-        }
-    }
-
     @Override
     protected Set<Channel> getAllChannels()
     {
-        return createChannels(channelNames);
+        return createChannels(channelDescriptions);
     }
 
     @Override
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/IHCSImageDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/IHCSImageDatasetLoader.java
index 4ac9f4aa60a..0a443b170ee 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/IHCSImageDatasetLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/IHCSImageDatasetLoader.java
@@ -26,9 +26,9 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.IHCSDatasetLoade
 public interface IHCSImageDatasetLoader extends IHCSDatasetLoader
 {
     /**
-     * @param chosenChannel start from 1
+     * @param chosenChannelCode start from 1
      * @return image (with absolute path, page and color)
      */
-    AbsoluteImageReference tryGetImage(String chosenChannel,
+    AbsoluteImageReference tryGetImage(String chosenChannelCode,
             ImageChannelStackReference channelStackReference, Size thumbnailSizeOrNull);
 }
\ No newline at end of file
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 e82fc4ec2b9..ada5d0c1423 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
@@ -42,6 +42,7 @@ import ch.systemsx.cisd.bds.hcs.Location;
 import ch.systemsx.cisd.bds.storage.IFile;
 import ch.systemsx.cisd.bds.storage.filesystem.NodeFactory;
 import ch.systemsx.cisd.common.collections.CollectionUtils;
+import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.filesystem.FileOperations;
@@ -78,7 +79,9 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImag
  * registration, but increases the performance when the user wants to see the image. Can be 'true'
  * or 'false', 'false' is the default value
  * <li>thumbnail-max-width, thumbnail-max-height - thumbnails size in pixels
- * <li>channel-names - names of the channels in which images have been acquired
+ * <li>[deprecated] channel-names - names of the channels in which images have been acquired
+ * <li>channel-codes - codes of the channels in which images have been acquired
+ * <li>channel-labels - labels of the channels in which images have been acquired
  * <li>well_geometry - format: [width]>x[height], e.g. 3x4. Specifies the grid into which a
  * microscope divided the well to acquire images.
  * <li>file-extractor - implementation of the {@link IHCSImageFileExtractor} interface which maps
@@ -122,16 +125,21 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
     private static final String DEPRECATED_FILE_EXTRACTOR_PROPERTY = "deprecated-file-extractor";
 
     // comma separated list of channel names, order matters
+    @Deprecated
     public static final String CHANNEL_NAMES = "channel-names";
 
+    // comma separated list of channel codes, order matters
+    public static final String CHANNEL_CODES = "channel-codes";
+
+    // comma separated list of channel labels, order matters
+    public static final String CHANNEL_LABELS = "channel-lables";
+
     // -----------
 
     private final DataSource dataSource;
 
     private final Geometry spotGeometry;
 
-    private final List<String> channelNames;
-
     private final int thumbnailMaxWidth;
 
     private final int thumbnailMaxHeight;
@@ -145,13 +153,14 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
 
     private IImagingQueryDAO currentTransaction;
 
+    private final List<ChannelDescription> channelDescriptions;
+
     public PlateStorageProcessor(final Properties properties)
     {
         super(properties);
         String spotGeometryText = getMandatoryProperty(SPOT_GEOMETRY_PROPERTY);
         this.spotGeometry = Geometry.createFromString(spotGeometryText);
-
-        this.channelNames = PropertyUtils.getMandatoryList(properties, CHANNEL_NAMES);
+        channelDescriptions = extractChannelDescriptions(properties);
         thumbnailMaxWidth =
                 PropertyUtils.getInt(properties, THUMBNAIL_MAX_WIDTH_PROPERTY,
                         DEFAULT_THUMBNAIL_MAX_WIDTH);
@@ -179,6 +188,46 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
         this.currentTransaction = null;
     }
 
+    public final static List<ChannelDescription> extractChannelDescriptions(
+            final Properties properties)
+    {
+        List<String> names = PropertyUtils.tryGetList(properties, CHANNEL_NAMES);
+        List<String> codes = PropertyUtils.tryGetList(properties, CHANNEL_CODES);
+        List<String> labels = PropertyUtils.tryGetList(properties, CHANNEL_LABELS);
+        if (names != null && (codes != null || labels != null))
+        {
+            throw new ConfigurationFailureException(String.format(
+                    "Configure either '%s' or ('%s','%s') but not both.", CHANNEL_NAMES,
+                    CHANNEL_CODES, CHANNEL_LABELS));
+        }
+        if (names != null)
+        {
+            List<ChannelDescription> descriptions = new ArrayList<ChannelDescription>();
+            for (String name : names)
+            {
+                descriptions.add(new ChannelDescription(name));
+            }
+            return descriptions;
+        }
+        if (codes == null || labels == null)
+        {
+            throw new ConfigurationFailureException(String.format(
+                    "Both '%s' and '%s' should be configured", CHANNEL_CODES, CHANNEL_LABELS));
+        }
+        if (codes.size() != labels.size())
+        {
+            throw new ConfigurationFailureException(String.format(
+                    "Number of configured '%s' should be the same as number of '%s'.",
+                    CHANNEL_CODES, CHANNEL_LABELS));
+        }
+        List<ChannelDescription> descriptions = new ArrayList<ChannelDescription>();
+        for (int i = 0; i < codes.size(); i++)
+        {
+            descriptions.add(new ChannelDescription(codes.get(i), labels.get(i)));
+        }
+        return descriptions;
+    }
+
     private IImagingQueryDAO createQuery()
     {
         return QueryTool.getQuery(dataSource, IImagingQueryDAO.class);
@@ -414,7 +463,12 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
     private HCSImageCheckList createImageCheckList(DataSetInformation dataSetInformation)
     {
         PlateDimension plateGeometry = getPlateGeometry(dataSetInformation);
-        return new HCSImageCheckList(channelNames, plateGeometry, spotGeometry);
+        List<String> channelCodes = new ArrayList<String>();
+        for (ChannelDescription cd : channelDescriptions)
+        {
+            channelCodes.add(cd.getCode());
+        }
+        return new HCSImageCheckList(channelCodes, plateGeometry, spotGeometry);
     }
 
     private HCSImageFileExtractionResult extractImages(final DataSetInformation dataSetInformation,
@@ -424,7 +478,9 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
         IHCSImageFileExtractor extractor = imageFileExtractor;
         if (extractor == null)
         {
-            extractor = adapt(deprecatedImageFileExtractor, incomingDataSetDirectory, channelNames);
+            extractor =
+                    adapt(deprecatedImageFileExtractor, incomingDataSetDirectory,
+                            channelDescriptions);
         }
         final HCSImageFileExtractionResult result =
                 extractor.extract(incomingDataSetDirectory, dataSetInformation);
@@ -649,10 +705,30 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
         return StorageFormat.PROPRIETARY;
     }
 
+    private static List<String> extractChannelCodes(final List<ChannelDescription> descriptions)
+    {
+        List<String> channelCodes = new ArrayList<String>();
+        for (ChannelDescription cd : descriptions)
+        {
+            channelCodes.add(cd.getCode());
+        }
+        return channelCodes;
+    }
+
+    private static List<String> extractChannelLabels(final List<ChannelDescription> descriptions)
+    {
+        List<String> channelLabels = new ArrayList<String>();
+        for (ChannelDescription cd : descriptions)
+        {
+            channelLabels.add(cd.getLabel());
+        }
+        return channelLabels;
+    }
+
     // adapts old-style image extractor to the new one which is stateless
     private static IHCSImageFileExtractor adapt(
             final ch.systemsx.cisd.etlserver.IHCSImageFileExtractor extractor,
-            final File imageFileRootDirectory, final List<String> channelNames)
+            final File imageFileRootDirectory, final List<ChannelDescription> descriptions)
     {
         return new IHCSImageFileExtractor()
             {
@@ -660,7 +736,8 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
                         DataSetInformation dataSetInformation)
                 {
                     HCSImageFileAccepter accepter =
-                            new HCSImageFileAccepter(imageFileRootDirectory, channelNames);
+                            new HCSImageFileAccepter(imageFileRootDirectory,
+                                    extractChannelCodes(descriptions));
                     ch.systemsx.cisd.etlserver.HCSImageFileExtractionResult originalResult =
                             extractor.process(NodeFactory
                                     .createDirectoryNode(incomingDataSetDirectory),
@@ -677,9 +754,10 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
                             new HashSet<HCSImageFileExtractionResult.Channel>();
                     for (Channel channel : channels)
                     {
-                        String name = getChannelName(channelNames, channel.getCounter());
-                        result.add(new HCSImageFileExtractionResult.Channel(name, null, channel
-                                .getWavelength()));
+                        result.add(new HCSImageFileExtractionResult.Channel(getChannelCodeOrLabel(
+                                extractChannelCodes(descriptions), channel.getCounter()), null,
+                                channel.getWavelength(), getChannelCodeOrLabel(
+                                        extractChannelLabels(descriptions), channel.getCounter())));
                     }
                     return result;
                 }
@@ -696,15 +774,15 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
             };
     }
 
-    private static String getChannelName(final List<String> channelNames, int channelId)
+    private static String getChannelCodeOrLabel(final List<String> channelCodes, int channelId)
     {
-        if (channelId > channelNames.size())
+        if (channelId > channelCodes.size())
         {
             throw UserFailureException.fromTemplate(
                     "Too large channel number %d, configured channels: %s.", channelId,
-                    CollectionUtils.abbreviate(channelNames, -1));
+                    CollectionUtils.abbreviate(channelCodes, -1));
         }
-        return channelNames.get(channelId - 1);
+        return channelCodes.get(channelId - 1);
     }
 
     private static final class HCSImageFileAccepter implements IHCSImageFileAccepter
@@ -713,12 +791,12 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
 
         private final File imageFileRootDirectory;
 
-        private final List<String> channelNames;
+        private final List<String> channelCodes;
 
-        public HCSImageFileAccepter(File imageFileRootDirectory, List<String> channelNames)
+        public HCSImageFileAccepter(File imageFileRootDirectory, List<String> channelCodes)
         {
             this.imageFileRootDirectory = imageFileRootDirectory;
-            this.channelNames = channelNames;
+            this.channelCodes = channelCodes;
         }
 
         public final void accept(final int channel, final Location wellLocation,
@@ -728,9 +806,9 @@ public final class PlateStorageProcessor extends AbstractStorageProcessor
                     FileUtilities.getRelativeFile(imageFileRootDirectory, new File(imageFile
                             .getPath()));
             assert imageRelativePath != null : "Image relative path should not be null.";
-            String channelName = getChannelName(channelNames, channel);
+            String channelCode = getChannelCodeOrLabel(channelCodes, channel);
             AcquiredPlateImage imageDesc =
-                    new AcquiredPlateImage(wellLocation, tileLocation, channelName, null, null,
+                    new AcquiredPlateImage(wellLocation, tileLocation, channelCode, null, null,
                             new RelativeImageReference(imageRelativePath, null, null));
             images.add(imageDesc);
         }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfoHelper.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfoHelper.java
index d8c418fc7c7..807d94a9d82 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfoHelper.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfoHelper.java
@@ -257,7 +257,7 @@ public class ScreeningContainerDatasetInfoHelper
 
     private static void addChannel(Map<String, Long> map, ImgChannelDTO channelDTO)
     {
-        map.put(channelDTO.getName(), channelDTO.getId());
+        map.put(channelDTO.getCode(), channelDTO.getId());
     }
 
     private static Map<String, ImgChannelDTO> asNameMap(List<ImgChannelDTO> channels)
@@ -265,7 +265,7 @@ public class ScreeningContainerDatasetInfoHelper
         Map<String, ImgChannelDTO> nameMap = new HashMap<String, ImgChannelDTO>();
         for (ImgChannelDTO channel : channels)
         {
-            nameMap.put(channel.getName(), channel);
+            nameMap.put(channel.getCode(), channel);
         }
         return nameMap;
     }
@@ -274,11 +274,11 @@ public class ScreeningContainerDatasetInfoHelper
             Map<String, ImgChannelDTO> existingChannels)
     {
         ImgChannelDTO channelDTO = makeChannelDTO(channel, expId);
-        String channelName = channelDTO.getName();
-        ImgChannelDTO existingChannel = existingChannels.get(channelName);
+        String channelCode = channelDTO.getCode();
+        ImgChannelDTO existingChannel = existingChannels.get(channelCode);
         if (existingChannel == null)
         {
-            throw createInvalidNewChannelException(expId, existingChannels, channelName);
+            throw createInvalidNewChannelException(expId, existingChannels, channelCode);
         }
         // a channel with a specified name already exists for an experiment, its description
         // will be updated. Wavelength will be updated only if it was null before.
@@ -291,8 +291,8 @@ public class ScreeningContainerDatasetInfoHelper
         {
             throw UserFailureException.fromTemplate(
                     "There are already datasets registered for the experiment "
-                            + "which use the same channel name, but with a different wavelength! "
-                            + "Channel %s, old wavelength %d, new wavelength %d.", channelName,
+                            + "which use the same channel code, but with a different wavelength! "
+                            + "Channel %s, old wavelength %d, new wavelength %d.", channelCode,
                     existingChannel.getWavelength(), channelDTO.getWavelength());
         }
         channelDTO.setId(existingChannel.getId());
@@ -305,7 +305,7 @@ public class ScreeningContainerDatasetInfoHelper
     {
         return UserFailureException.fromTemplate(
                 "Experiment with id '%d' has already some channels registered "
-                        + "and does not have a channel with a name '%s'. "
+                        + "and does not have a channel with a code '%s'. "
                         + "Register a new experiment to use new channels. "
                         + "Available channel names in this experiment: %s.", expId, channelName,
                 existingChannels.keySet());
@@ -322,7 +322,7 @@ public class ScreeningContainerDatasetInfoHelper
     private static ImgChannelDTO makeChannelDTO(HCSImageFileExtractionResult.Channel channel,
             long expId)
     {
-        return ImgChannelDTO.createExperimentChannel(channel.getName(),
-                channel.tryGetDescription(), channel.tryGetWavelength(), expId);
+        return ImgChannelDTO.createExperimentChannel(channel.getCode(),
+                channel.tryGetDescription(), channel.tryGetWavelength(), expId, channel.getLabel());
     }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java
index 05f96a3579f..04caa8b4268 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java
@@ -65,13 +65,13 @@ public class HCSImageDatasetLoader extends HCSDatasetLoader implements IHCSImage
     }
 
     /**
-     * @param chosenChannel start from 1
+     * @param chosenChannelCode 
      * @return image (with absolute path, page and color)
      */
-    public AbsoluteImageReference tryGetImage(String chosenChannel,
+    public AbsoluteImageReference tryGetImage(String chosenChannelCode,
             ImageChannelStackReference channelStackReference, Size thumbnailSizeOrNull)
     {
-        assert StringUtils.isBlank(chosenChannel) == false;
+        assert StringUtils.isBlank(chosenChannelCode) == false;
         LocationImageChannelStackReference stackLocations =
                 channelStackReference.tryGetChannelStackLocations();
         if (stackLocations != null)
@@ -84,8 +84,8 @@ public class HCSImageDatasetLoader extends HCSDatasetLoader implements IHCSImage
         }
 
         Long chosenChannelId =
-                query.tryGetChannelIdByChannelNameDatasetIdOrExperimentId(getDataset().getId(),
-                        getContainer().getExperimentId(), chosenChannel);
+                query.tryGetChannelIdByChannelCodeDatasetIdOrExperimentId(getDataset().getId(),
+                        getContainer().getExperimentId(), chosenChannelCode);
         if (chosenChannelId == null)
         {
             return null;
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 4361be170e0..44e38f70787 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
@@ -36,6 +36,7 @@ import ch.systemsx.cisd.bds.hcs.Location;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.openbis.dss.etl.AbstractHCSImageFileExtractor;
 import ch.systemsx.cisd.openbis.dss.etl.AcquiredPlateImage;
+import ch.systemsx.cisd.openbis.dss.etl.ChannelDescription;
 import ch.systemsx.cisd.openbis.dss.etl.HCSImageFileExtractionResult.Channel;
 import ch.systemsx.cisd.openbis.dss.etl.dynamix.WellLocationMappingUtils.DynamixWellPosition;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
@@ -52,32 +53,32 @@ public class HCSImageFileExtractor extends AbstractHCSImageFileExtractor
 
     private static final String POSITION_MAPPING_FILE_NAME = "pos2loc.tsv";
 
-    private final List<String> channelNames;
+    private final List<ChannelDescription> channelDescriptions;
 
     private final Map<File/* mapping file */, Map<DynamixWellPosition, WellLocation>> wellLocationMapCache;
 
     public HCSImageFileExtractor(final Properties properties)
     {
         super(properties);
-        this.channelNames = extractChannelNames(properties);
+        this.channelDescriptions = tryExtractChannelDescriptions(properties);
         this.wellLocationMapCache = new HashMap<File, Map<DynamixWellPosition, WellLocation>>();
     }
 
     @Override
     protected final Set<Channel> getAllChannels()
     {
-        return createChannels(channelNames);
+        return createChannels(channelDescriptions);
     }
 
     @Override
     protected final List<AcquiredPlateImage> getImages(String channelToken, Location plateLocation,
             Location wellLocation, Float timepointOrNull, String imageRelativePath)
     {
-        String channelName = channelToken.toUpperCase();
-        ensureChannelExist(channelNames, channelName);
+        String channelCode = channelToken.toUpperCase();
+        ensureChannelExist(channelDescriptions, channelCode);
 
         List<AcquiredPlateImage> images = new ArrayList<AcquiredPlateImage>();
-        images.add(createImage(plateLocation, wellLocation, imageRelativePath, channelName,
+        images.add(createImage(plateLocation, wellLocation, imageRelativePath, channelCode,
                 timepointOrNull, null));
         return images;
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/MergingImagesDownloadServlet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/MergingImagesDownloadServlet.java
index 7dab3727995..66e2891bb99 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/MergingImagesDownloadServlet.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/MergingImagesDownloadServlet.java
@@ -48,8 +48,8 @@ public class MergingImagesDownloadServlet extends AbstractImagesDownloadServlet
         List<AbsoluteImageReference> images =
                 ImageChannelsUtils.getImagePaths(datasetRoot, datasetCode, params);
         BufferedImage image = ImageChannelsUtils.mergeImageChannels(params, images);
-        String singleFileNameOrNull = images.size() == 1 ? images.get(0).getContent().getName() : null;
+        String singleFileNameOrNull =
+                images.size() == 1 ? images.get(0).getContent().getName() : null;
         return createResponseContentStream(image, singleFileNameOrNull);
     }
-
 }
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 9b3f568fc19..e23282d2e1b 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
@@ -57,7 +57,7 @@ public class ImageChannelsUtils
         Size thumbnailSizeOrNull = params.tryGetThumbnailSize();
         if (params.isMergeAllChannels())
         {
-            for (String chosenChannel : imageAccessor.getImageParameters().getChannelsNames())
+            for (String chosenChannel : imageAccessor.getImageParameters().getChannelsCodes())
             {
                 AbsoluteImageReference image =
                         getImage(imageAccessor, params.getChannelStack(), chosenChannel,
@@ -243,16 +243,16 @@ public class ImageChannelsUtils
     // --------- common
 
     /**
-     * @param chosenChannel starts from 1
+     * @param chosenChannelCode starts from 1
      * @throw {@link EnvironmentFailureException} when image does not exist
      */
     public static AbsoluteImageReference getImage(IHCSImageDatasetLoader imageAccessor,
-            ImageChannelStackReference channelStackReference, String chosenChannel,
+            ImageChannelStackReference channelStackReference, String chosenChannelCode,
             Size thumbnailSizeOrNull)
     {
         AbsoluteImageReference image =
                 imageAccessor
-                        .tryGetImage(chosenChannel, channelStackReference, thumbnailSizeOrNull);
+                        .tryGetImage(chosenChannelCode, channelStackReference, thumbnailSizeOrNull);
         if (image != null)
         {
             return image;
@@ -261,7 +261,7 @@ public class ImageChannelsUtils
             throw EnvironmentFailureException.fromTemplate("No "
                     + (thumbnailSizeOrNull != null ? "thumbnail" : "image")
                     + " found for channel stack %s and channel %s", channelStackReference,
-                    chosenChannel);
+                    chosenChannelCode);
         }
     }
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
index 4e455a3a299..aec92e1894a 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
@@ -172,7 +172,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements
         PlateImageParameters params = imageAccessor.getImageParameters();
         int tilesNumber = params.getTileColsNum() * params.getTileRowsNum();
         BufferedImage image = ImageUtil.loadImage(imageFile.getInputStream());
-        return new ImageDatasetMetadata(dataset, params.getChannelsNames(), tilesNumber, image
+        return new ImageDatasetMetadata(dataset, params.getChannelsCodes(), tilesNumber, image
                 .getWidth(), image.getHeight());
     }
 
@@ -185,12 +185,12 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements
             for (int col = 1; col <= params.getColsNum(); col++)
             {
                 AbsoluteImageReference image;
-                for (String channelName : params.getChannelsNames())
+                for (String channelCode : params.getChannelsCodes())
                 {
                     ImageChannelStackReference channelStackReference =
                             ImageChannelStackReference.createFromLocations(new Location(col, row),
                                     new Location(1, 1));
-                    image = imageAccessor.tryGetImage(channelName, channelStackReference, null);
+                    image = imageAccessor.tryGetImage(channelCode, channelStackReference, null);
                     if (image != null)
                     {
                         return image.getContent();
@@ -266,7 +266,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements
         }
         return result;
     }
-    
+
     private List<String> getCodes(FeatureTableBuilder builder)
     {
         List<CodeAndLabel> featureCodesAndLabels = builder.getCodesAndLabels();
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ChannelComboBox.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ChannelComboBox.java
index a324e7318fc..bd940db43ad 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ChannelComboBox.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ChannelComboBox.java
@@ -50,7 +50,7 @@ public class ChannelComboBox extends SimpleComboBox<String>
     public ChannelComboBox(List<String> names, String initialValue)
     {
         this();
-        addUniqueNames(names);
+        addUniqueCodes(names);
         if (initialValue != null)
         {
             setSimpleValue(initialValue);
@@ -74,11 +74,11 @@ public class ChannelComboBox extends SimpleComboBox<String>
     /**
      * Adds names to the combo box if they were not yet present.
      */
-    private void addUniqueNames(List<String> names)
+    private void addUniqueCodes(List<String> codes)
     {
         List<String> withMerged = new ArrayList<String>();
         withMerged.add(ScreeningConstants.MERGED_CHANNELS);
-        withMerged.addAll(names);
+        withMerged.addAll(codes);
         for (String s : withMerged)
         {
             if (findModel(s) == null)
@@ -88,10 +88,10 @@ public class ChannelComboBox extends SimpleComboBox<String>
         }
     }
 
-    public void addNamesAndListener(List<String> newNames,
+    public void addCodesAndListener(List<String> newCodes,
             SelectionChangedListener<SimpleComboValue<String>> listener)
     {
-        addUniqueNames(newNames);
+        addUniqueCodes(newCodes);
         addSelectionChangedListener(listener);
         autoselect();
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateMaterialReviewer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateMaterialReviewer.java
index b851d3b98fc..bed0c97cd2b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateMaterialReviewer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateMaterialReviewer.java
@@ -391,7 +391,7 @@ public class PlateMaterialReviewer extends AbstractSimpleBrowserGrid<WellContent
                             new ChannelWidgetWithListener(viewerFactory);
                     widgetWithListener.update(channelChooser.getSimpleValue());
 
-                    channelChooser.addNamesAndListener(imageParameters.getChannelsNames(),
+                    channelChooser.addCodesAndListener(imageParameters.getChannelsCodes(),
                             widgetWithListener.asSelectionChangedListener());
                     return widgetWithListener.asWidget();
                 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
index 263c9a1721b..d435ff38bf3 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
@@ -130,7 +130,7 @@ public class WellContentDialog extends Dialog
             return new Text("Incorrect well code.");
         }
         PlateImageParameters imageParameters = imageDataset.getImageParameters();
-        if (imageParameters.getChannelsNames().contains(channel) == false
+        if (imageParameters.getChannelsCodes().contains(channel) == false
                 && channel.equals(ScreeningConstants.MERGED_CHANNELS) == false)
         {
             return new Text("No images available for this channel.");
@@ -197,7 +197,7 @@ public class WellContentDialog extends Dialog
                 }
             };
         return ChannelChooser.createViewerWithChannelChooser(viewerFactory, channelState, images
-                .getChannelsNames());
+                .getChannelsCodes());
     }
 
     private static LayoutContainer createTilesGrid(final WellImages images, String channel,
@@ -266,7 +266,7 @@ public class WellContentDialog extends Dialog
                 }
             };
         return ChannelChooser.createViewerWithChannelChooser(viewerFactory, channelState, images
-                .getChannelsNames());
+                .getChannelsCodes());
     }
 
     // ---------------- STATIC METHODS -------------------
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellImages.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellImages.java
index f6eb0f92499..a3873a74ee7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellImages.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellImages.java
@@ -55,9 +55,9 @@ public class WellImages
         return imageParams.getTileColsNum();
     }
 
-    public List<String> getChannelsNames()
+    public List<String> getChannelsCodes()
     {
-        return imageParams.getChannelsNames();
+        return imageParams.getChannelsCodes();
     }
 
     public boolean isMultidimensional()
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/ImageDatasetMetadata.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/ImageDatasetMetadata.java
index 517b00b9d44..38e1627fa8d 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/ImageDatasetMetadata.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/ImageDatasetMetadata.java
@@ -50,7 +50,7 @@ public class ImageDatasetMetadata implements Serializable
     }
 
     /**
-     * names of channels in which images have been acquired for the described dataset
+     * codes of channels in which images have been acquired for the described dataset
      */
     public List<String> getChannelNames()
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/PlateImageReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/PlateImageReference.java
index 6aad66651ec..88403903f3c 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/PlateImageReference.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/PlateImageReference.java
@@ -42,7 +42,7 @@ public class PlateImageReference extends DatasetIdentifier
     }
 
     /**
-     * channel name
+     * channel code
      */
     public String getChannel()
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImageParameters.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImageParameters.java
index 5f3dbc41fcd..feca4ddf712 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImageParameters.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImageParameters.java
@@ -38,7 +38,7 @@ public class PlateImageParameters implements IsSerializable
 
     private int tileColsNum;
 
-    private List<String> channelsNames;
+    private List<String> channelsCodes;
 
     // true if any well in the dataset has a time series (or depth stack) of images
     private boolean isMultidimensional;
@@ -93,19 +93,19 @@ public class PlateImageParameters implements IsSerializable
         this.datasetCode = datasetCode;
     }
 
-    public void setChannelsNames(List<String> channelsNames)
+    public void setChannelsCodes(List<String> channelsCodes)
     {
-        this.channelsNames = channelsNames;
+        this.channelsCodes = channelsCodes;
     }
 
-    public List<String> getChannelsNames()
+    public List<String> getChannelsCodes()
     {
-        return channelsNames;
+        return channelsCodes;
     }
 
     public int getChannelsNumber()
     {
-        return channelsNames.size();
+        return channelsCodes.size();
     }
 
     public boolean isMultidimensional()
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/HCSDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/HCSDatasetLoader.java
index dab333851d1..0f56582e1a1 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/HCSDatasetLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/HCSDatasetLoader.java
@@ -47,7 +47,7 @@ public class HCSDatasetLoader implements IHCSDatasetLoader
 
     protected Integer channelCount;
 
-    protected List<String> channelNames;
+    protected List<String> channelCodes;
 
     public HCSDatasetLoader(IImagingQueryDAO query, String datasetPermId)
     {
@@ -57,10 +57,10 @@ public class HCSDatasetLoader implements IHCSDatasetLoader
         {
             throw new IllegalStateException(String.format("Dataset '%s' not found", datasetPermId));
         }
-        String[] namesAsArray =
-                query.getChannelNamesByDatasetIdOrExperimentId(getDataset().getId(), getContainer()
+        String[] codesAsArray =
+                query.getChannelCodesByDatasetIdOrExperimentId(getDataset().getId(), getContainer()
                         .getExperimentId());
-        this.channelNames = new ArrayList<String>(Arrays.asList(namesAsArray));
+        this.channelCodes = new ArrayList<String>(Arrays.asList(codesAsArray));
     }
 
     /** has to be called at the end */
@@ -85,7 +85,7 @@ public class HCSDatasetLoader implements IHCSDatasetLoader
 
     public int getChannelCount()
     {
-        return channelNames.size();
+        return channelCodes.size();
     }
 
     public List<WellImageChannelStack> listImageChannelStacks(WellLocation wellLocation)
@@ -122,12 +122,12 @@ public class HCSDatasetLoader implements IHCSDatasetLoader
         params.setTileRowsNum(getDataset().getFieldNumberOfRows());
         params.setTileColsNum(getDataset().getFieldNumberOfColumns());
         params.setIsMultidimensional(dataset.getIsMultidimensional());
-        List<String> escapedChannelNames = new ArrayList<String>();
-        for (String name : channelNames)
+        List<String> escapedChannelCodes = new ArrayList<String>();
+        for (String name : channelCodes)
         {
-            escapedChannelNames.add(StringEscapeUtils.escapeCsv(name));
+            escapedChannelCodes.add(StringEscapeUtils.escapeCsv(name));
         }
-        params.setChannelsNames(escapedChannelNames);
+        params.setChannelsCodes(escapedChannelCodes);
         return params;
     }
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingQueryDAO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingQueryDAO.java
index cc45c98716c..be84f753092 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingQueryDAO.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingQueryDAO.java
@@ -108,8 +108,8 @@ public interface IImagingQueryDAO extends TransactionQuery
     @Select("select count(*) from CHANNELS where DS_ID = ?{1} or EXP_ID = ?{2}")
     public int countChannelByDatasetIdOrExperimentId(long datasetId, long experimentId);
 
-    @Select("select label from CHANNELS where DS_ID = ?{1} or EXP_ID = ?{2} order by LABEL")
-    public String[] getChannelNamesByDatasetIdOrExperimentId(long datasetId, long experimentId);
+    @Select("select code from CHANNELS where DS_ID = ?{1} or EXP_ID = ?{2} order by CODE")
+    public String[] getChannelCodesByDatasetIdOrExperimentId(long datasetId, long experimentId);
 
     @Select(sql = "select id from CHANNELS where DS_ID = ?{1} or EXP_ID = ?{2} order by LABEL", fetchSize = FETCH_SIZE)
     public long[] getChannelIdsByDatasetIdOrExperimentId(long datasetId, long experimentId);
@@ -154,7 +154,7 @@ public interface IImagingQueryDAO extends TransactionQuery
     public long addExperiment(String experimentPermId);
 
     @Select("insert into CHANNELS (LABEL, CODE, DESCRIPTION, WAVELENGTH, DS_ID, EXP_ID) values "
-            + "(?{1.name}, ?{1.name}, ?{1.description}, ?{1.wavelength}, ?{1.datasetId}, ?{1.experimentId}) returning ID")
+            + "(?{1.label}, ?{1.code}, ?{1.description}, ?{1.wavelength}, ?{1.datasetId}, ?{1.experimentId}) returning ID")
     public long addChannel(ImgChannelDTO channel);
 
     @Select("insert into CONTAINERS (PERM_ID, SPOTS_WIDTH, SPOTS_HEIGHT, EXPE_ID) values "
@@ -186,8 +186,8 @@ public interface IImagingQueryDAO extends TransactionQuery
             + "where ID = ?{1.id}")
     public void updateChannel(ImgChannelDTO channel);
 
-    @Select("select ID from CHANNELS where (DS_ID = ?{1} or EXP_ID = ?{2}) and LABEL = upper(?{3})")
-    public Long tryGetChannelIdByChannelNameDatasetIdOrExperimentId(long id, long experimentId,
-            String chosenChannel);
+    @Select("select ID from CHANNELS where (DS_ID = ?{1} or EXP_ID = ?{2}) and CODE = upper(?{3})")
+    public Long tryGetChannelIdByChannelCodeDatasetIdOrExperimentId(long id, long experimentId,
+            String chosenChannelCode);
 
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgChannelDTO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgChannelDTO.java
index 69ab6ac7936..0072348e2b1 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgChannelDTO.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgChannelDTO.java
@@ -30,7 +30,10 @@ public class ImgChannelDTO extends AbstractHashable
     private long id;
 
     @ResultColumn("LABEL")
-    private String name;
+    private String label;
+
+    @ResultColumn("CODE")
+    private String code;
 
     @ResultColumn("DESCRIPTION")
     private String descriptionOrNull;
@@ -46,16 +49,17 @@ public class ImgChannelDTO extends AbstractHashable
     @ResultColumn("EXP_ID")
     private Long experimentIdOrNull;
 
-    public static ImgChannelDTO createDatasetChannel(String name, String descriptionOrNull,
-            Integer wavelengthOrNull, long datasetId)
+    public static ImgChannelDTO createDatasetChannel(String code, String descriptionOrNull,
+            Integer wavelengthOrNull, long datasetId, String label)
     {
-        return new ImgChannelDTO(name, descriptionOrNull, wavelengthOrNull, datasetId, null);
+        return new ImgChannelDTO(code, descriptionOrNull, wavelengthOrNull, datasetId, null, label);
     }
 
-    public static ImgChannelDTO createExperimentChannel(String name, String descriptionOrNull,
-            Integer wavelengthOrNull, long experimentId)
+    public static ImgChannelDTO createExperimentChannel(String code, String descriptionOrNull,
+            Integer wavelengthOrNull, long experimentId, String label)
     {
-        return new ImgChannelDTO(name, descriptionOrNull, wavelengthOrNull, null, experimentId);
+        return new ImgChannelDTO(code, descriptionOrNull, wavelengthOrNull, null, experimentId,
+                label);
     }
 
     private ImgChannelDTO()
@@ -63,12 +67,13 @@ public class ImgChannelDTO extends AbstractHashable
         // All Data-Object classes must have a default constructor.
     }
 
-    private ImgChannelDTO(String name, String descriptionOrNull, Integer wavelengthOrNull,
-            Long datasetIdOrNull, Long experimentIdOrNull)
+    private ImgChannelDTO(String code, String descriptionOrNull, Integer wavelengthOrNull,
+            Long datasetIdOrNull, Long experimentIdOrNull, String label)
     {
         assert (datasetIdOrNull == null && experimentIdOrNull != null)
                 || (datasetIdOrNull != null && experimentIdOrNull == null);
-        this.name = name.toUpperCase();
+        this.code = code.toUpperCase();
+        this.label = label;
         this.descriptionOrNull = descriptionOrNull;
         this.wavelengthOrNull = wavelengthOrNull;
         this.datasetIdOrNull = datasetIdOrNull;
@@ -85,14 +90,14 @@ public class ImgChannelDTO extends AbstractHashable
         this.id = id;
     }
 
-    public String getName()
+    public String getCode()
     {
-        return name;
+        return code;
     }
 
-    public void setName(String name)
+    public void setCode(String code)
     {
-        this.name = name;
+        this.code = code;
     }
 
     public String getDescription()
@@ -105,6 +110,16 @@ public class ImgChannelDTO extends AbstractHashable
         this.descriptionOrNull = description;
     }
 
+    public String getLabel()
+    {
+        return label;
+    }
+
+    public void setLabel(String label)
+    {
+        this.label = label;
+    }
+
     /** can be null */
     public Integer getWavelength()
     {
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImagingQueryDAOTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImagingQueryDAOTest.java
index 7245fdbe9cc..e542bb1943d 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImagingQueryDAOTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImagingQueryDAOTest.java
@@ -42,6 +42,8 @@ import ch.systemsx.cisd.bds.hcs.Location;
 public class ImagingQueryDAOTest extends AbstractDBTest
 {
 
+    private static final String CHANNEL_LABEL = "Channel Label";
+
     private static final int PAGE = 1;
 
     private static final int Y_TILE_ROW = 2;
@@ -162,7 +164,7 @@ public class ImagingQueryDAOTest extends AbstractDBTest
         // test countChannelByDatasetIdOrExperimentId
         assertEquals(2, dao.countChannelByDatasetIdOrExperimentId(datasetId, experimentId));
         String[] channelNames =
-                dao.getChannelNamesByDatasetIdOrExperimentId(datasetId, experimentId);
+                dao.getChannelCodesByDatasetIdOrExperimentId(datasetId, experimentId);
         assertEquals("DSCHANNEL", channelNames[0]);
         assertEquals("EXPCHANNEL", channelNames[1]);
 
@@ -173,7 +175,7 @@ public class ImagingQueryDAOTest extends AbstractDBTest
                 || channels[1] == channelId1 && channels[0] == channelId2);
 
         // test get id of first channel
-        assertEquals(channels[0], dao.tryGetChannelIdByChannelNameDatasetIdOrExperimentId(
+        assertEquals(channels[0], dao.tryGetChannelIdByChannelCodeDatasetIdOrExperimentId(
                 datasetId, experimentId, "dsChannel").intValue());
 
         List<ImgChannelDTO> experimentChannels = dao.getChannelsByExperimentId(experimentId);
@@ -253,7 +255,7 @@ public class ImagingQueryDAOTest extends AbstractDBTest
     {
         final ImgChannelDTO channel =
                 ImgChannelDTO.createDatasetChannel(DS_CHANNEL, CHANNEL_DESCRIPTION, WAVELENGTH,
-                        datasetId);
+                        datasetId, CHANNEL_LABEL);
         return dao.addChannel(channel);
     }
 
@@ -261,7 +263,7 @@ public class ImagingQueryDAOTest extends AbstractDBTest
     {
         final ImgChannelDTO channel =
                 ImgChannelDTO.createExperimentChannel(EXP_CHANNEL, CHANNEL_DESCRIPTION, WAVELENGTH,
-                        experimentId);
+                        experimentId, CHANNEL_LABEL);
         return dao.addChannel(channel);
     }
 
-- 
GitLab