diff --git a/bds/source/java/ch/systemsx/cisd/bds/Constants.java b/bds/source/java/ch/systemsx/cisd/bds/Constants.java
index f2b532f50d1b5e1cd44cf4ffd92fa36ed91b0f7c..c633937130f90e1707cd1557b99ba6e705f63d1c 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/Constants.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/Constants.java
@@ -16,6 +16,9 @@
 
 package ch.systemsx.cisd.bds;
 
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
 /**
  * Some constants used inside the <i>BDS</i> library
  * 
@@ -24,9 +27,15 @@ package ch.systemsx.cisd.bds;
 public final class Constants
 {
 
+    /** The date format pattern. */
+    private static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss Z";
+
     /** The only accepted path separator (system independent). */
     public final static char PATH_SEPARATOR = '/';
 
+    /** The uniformly date format used. */
+    public static final DateFormat DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_PATTERN);
+
     private Constants()
     {
         // Can not be instantiated.
diff --git a/bds/source/java/ch/systemsx/cisd/bds/DataSet.java b/bds/source/java/ch/systemsx/cisd/bds/DataSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..ceddcad0653e692f86a0bc4e6c9570b7500c7b19
--- /dev/null
+++ b/bds/source/java/ch/systemsx/cisd/bds/DataSet.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2008 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.bds;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import ch.systemsx.cisd.bds.exception.DataStructureException;
+import ch.systemsx.cisd.bds.storage.IDirectory;
+
+/**
+ * Identifier of the data set. This is an immutable but extendable value object class. An instance
+ * of this class allows unique identification in the database.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class DataSet implements IStorable
+{
+    static final String FOLDER = "data_set";
+
+    static final String CODE = "code";
+
+    static final String PRODUCTION_TIMESTAMP = "production_date";
+
+    static final String PRODUCER_CODE = "producer_code";
+
+    static final String OBSERVABLE_TYPE = "observable_type";
+
+    static final String IS_MEASURED = "is_measured";
+
+    static final String PARENT_CODES = "parent_codes";
+
+    /** This data set unique identifier. */
+    private final String code;
+
+    /** Provides the information when the data set has been created. */
+    private final Date productionTimestamp;
+
+    /** Identifies the "device" that produced this data set. */
+    private final String producerCode;
+
+    /** Is a code that describes the type of data that is stored in this standard. */
+    private final ObservableType observableType;
+
+    /**
+     * Specifies whether the data set has been measured from a sample or whether it has been derived
+     * by means of some calculation from another data set.
+     */
+    private final boolean isMeasured;
+
+    /** The list of parent codes. Never <code>null</code> but could be empty. */
+    private final List<String> parentCodes;
+
+    /**
+     * Creates an instance of data set.
+     * 
+     * @param code A non-empty string of the data set code. Can not be empty.
+     * @param observableType type of this data set. Can not be <code>null</code>.
+     * @param isMeasured measured or derived.
+     * @param productionTimestampOrNull production timestamp or <code>null</code> if unknown.
+     * @param producerCodeOrNull producer code (aka "device id") or <code>null</code> if unknown.
+     * @param parentCodesOrNull list of parent data sets. Must be <code>null</code> or empty for
+     *            measured data (or not empty for derived data).
+     */
+    public DataSet(final String code, final ObservableType observableType,
+            final boolean isMeasured, final Date productionTimestampOrNull,
+            final String producerCodeOrNull, final List<String> parentCodesOrNull)
+    {
+        assert StringUtils.isEmpty(code) == false : "Unspecified data set code.";
+        this.code = code;
+        this.isMeasured = isMeasured;
+        assert observableType != null : "Observable type can not be null.";
+        this.observableType = observableType;
+        if (isMeasured == false)
+        {
+            assert parentCodesOrNull != null && parentCodesOrNull.size() > 0 : "Unspecified parent codes.";
+            this.parentCodes = parentCodesOrNull;
+        } else
+        {
+            assert parentCodesOrNull == null || parentCodesOrNull.size() == 0 : "No parent can be specified for derived data.";
+            this.parentCodes = Collections.<String> emptyList();
+        }
+        this.producerCode = producerCodeOrNull;
+        this.productionTimestamp = productionTimestampOrNull;
+    }
+
+    public final String getCode()
+    {
+        return code;
+    }
+
+    public final Date getProductionTimestamp()
+    {
+        return productionTimestamp;
+    }
+
+    public final String getProducerCode()
+    {
+        return producerCode;
+    }
+
+    public final ObservableType getObservableType()
+    {
+        return observableType;
+    }
+
+    public final boolean isMeasured()
+    {
+        return isMeasured;
+    }
+
+    public final List<String> getParentCodes()
+    {
+        return parentCodes;
+    }
+
+    /**
+     * Loads the experiment identifier from the specified directory.
+     * 
+     * @throws DataStructureException if file missing.
+     */
+    static DataSet loadFrom(final IDirectory directory)
+    {
+        final IDirectory idFolder = Utilities.getSubDirectory(directory, FOLDER);
+        final String code = Utilities.getTrimmedString(idFolder, CODE);
+        ObservableType observableType = null;
+        try
+        {
+            observableType =
+                    ObservableType.getObservableTypeCode(Utilities.getTrimmedString(idFolder,
+                            OBSERVABLE_TYPE));
+        } catch (final IllegalArgumentException ex)
+        {
+            throw new DataStructureException(ex.getMessage());
+        }
+        final boolean isMeasured = Utilities.getBoolean(idFolder, IS_MEASURED);
+        final Date productionTimestampOrNull =
+                Utilities.getDateOrNull(idFolder, PRODUCTION_TIMESTAMP);
+        final String producerCodeOrNull = Utilities.getTrimmedString(idFolder, PRODUCER_CODE);
+        final List<String> parentCodes = Utilities.getStringList(idFolder, PARENT_CODES);
+        return new DataSet(code, observableType, isMeasured, productionTimestampOrNull,
+                producerCodeOrNull, parentCodes);
+    }
+
+    //
+    // IStorable
+    //
+
+    public final void saveTo(final IDirectory directory)
+    {
+        final IDirectory folder = directory.makeDirectory(FOLDER);
+        folder.addKeyValuePair(CODE, code);
+        folder.addKeyValuePair(PRODUCTION_TIMESTAMP,
+                productionTimestamp == null ? StringUtils.EMPTY_STRING : Constants.DATE_FORMAT
+                        .format(productionTimestamp));
+        folder.addKeyValuePair(PRODUCER_CODE, StringUtils.emptyIfNull(producerCode));
+        folder.addKeyValuePair(IS_MEASURED, Boolean.toString(isMeasured));
+
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public final boolean equals(final Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+        if (obj instanceof DataSet == false)
+        {
+            return false;
+        }
+        final DataSet that = (DataSet) obj;
+        return that.code.equals(code);
+    }
+
+    @Override
+    public final int hashCode()
+    {
+        int result = 17;
+        result = 37 * result + code.hashCode();
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java b/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java
index dcb9c40d9cec09e5e05f324dcb339affbc1da3af..7b03850edb815b9bfa3f5fb8935e5b6e279650bd 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java
@@ -90,37 +90,39 @@ public class DataStructureV1_0 extends AbstractDataStructure
         return Utilities.getOrCreateSubDirectory(getDataDirectory(), DIR_STANDARD);
     }
 
-    private IDirectory getDataDirectory()
+    private final IDirectory getDataDirectory()
     {
         assertOpenOrCreated();
         return Utilities.getOrCreateSubDirectory(root, DIR_DATA);
     }
 
-    private IDirectory getMetaDataDirectory()
+    private final IDirectory getMetaDataDirectory()
     {
         assertOpenOrCreated();
         return Utilities.getOrCreateSubDirectory(root, DIR_METADATA);
     }
 
-    private IDirectory getAnnotationsDirectory()
+    private final IDirectory getAnnotationsDirectory()
     {
         assertOpenOrCreated();
         return Utilities.getOrCreateSubDirectory(root, DIR_ANNOTATIONS);
     }
 
-    private IDirectory getParametersDirectory()
+    private final IDirectory getParametersDirectory()
     {
         assertOpenOrCreated();
         return Utilities.getOrCreateSubDirectory(getMetaDataDirectory(), DIR_PARAMETERS);
     }
 
     /**
-     * Returns the formatted data. This method can be called only after method {@link #setFormat(Format)} has been
-     * invoked. If the format is not known {@link UnknownFormatV1_0} will be assumed.
+     * Returns the formatted data. This method can be called only after method
+     * {@link #setFormat(Format)} has been invoked. If the format is not known
+     * {@link UnknownFormatV1_0} will be assumed.
      * 
-     * @throws DataStructureException if this method has been invoked before the format has been set.
+     * @throws DataStructureException if this method has been invoked before the format has been
+     *             set.
      */
-    public IFormattedData getFormattedData() throws DataStructureException
+    public final IFormattedData getFormattedData() throws DataStructureException
     {
         assertOpenOrCreated();
         if (format == null)
@@ -146,15 +148,16 @@ public class DataStructureV1_0 extends AbstractDataStructure
     /**
      * Adds the specified format parameter.
      * 
-     * @throws IllegalArgumentException if they is already a parameter with same name as <code>parameter</code>.
+     * @throws IllegalArgumentException if they is already a parameter with same name as
+     *             <code>parameter</code>.
      */
-    public void addFormatParameter(final FormatParameter formatParameter)
+    public final void addFormatParameter(final FormatParameter formatParameter)
     {
         assert formatParameter != null : "Unspecified format parameter.";
         formatParameters.addParameter(formatParameter);
     }
 
-    public void setAnnotations(final IAnnotations annotations)
+    public final void setAnnotations(final IAnnotations annotations)
     {
         this.annotations = annotations;
     }
@@ -162,8 +165,8 @@ public class DataStructureV1_0 extends AbstractDataStructure
     /**
      * Returns the experiment identifier.
      * 
-     * @throws DataStructureException if the experiment identifier hasn't be loaded nor hasn't be set by
-     *             {@link #setExperimentIdentifier(ExperimentIdentifier)}.
+     * @throws DataStructureException if the experiment identifier hasn't be loaded nor hasn't be
+     *             set by {@link #setExperimentIdentifier(ExperimentIdentifier)}.
      */
     public ExperimentIdentifier getExperimentIdentifier()
     {
@@ -174,7 +177,7 @@ public class DataStructureV1_0 extends AbstractDataStructure
     /**
      * Sets the experiment identifier. Overwrites an already set or loaded value.
      */
-    public void setExperimentIdentifier(final ExperimentIdentifier id)
+    public final void setExperimentIdentifier(final ExperimentIdentifier id)
     {
         assert id != null : "Unspecified experiment identifier";
         assertOpenOrCreated();
@@ -185,18 +188,18 @@ public class DataStructureV1_0 extends AbstractDataStructure
      * Returns the date of registration of the experiment.
      * 
      * @throws DataStructureException if the processing type hasn't be loaded nor hasn't be set by
-     *             {@link #setExperimentRegistrator(ExperimentRegistrator)}.
+     *             {@link #setExperimentRegistrationTimestamp(ExperimentRegistrationTimestamp)}.
      */
-    public ExperimentRegistratorDate getExperimentRegistratorDate()
+    public final ExperimentRegistrationTimestamp getExperimentRegistratorTimestamp()
     {
         assertOpenOrCreated();
-        return ExperimentRegistratorDate.loadFrom(getMetaDataDirectory());
+        return ExperimentRegistrationTimestamp.loadFrom(getMetaDataDirectory());
     }
 
     /**
      * Sets the date of registration of the experiment.
      */
-    public void setExperimentRegistrationDate(final ExperimentRegistratorDate date)
+    public final void setExperimentRegistrationTimestamp(final ExperimentRegistrationTimestamp date)
     {
         assertOpenOrCreated();
         date.saveTo(getMetaDataDirectory());
@@ -208,13 +211,13 @@ public class DataStructureV1_0 extends AbstractDataStructure
      * @throws DataStructureException if the processing type hasn't be loaded nor hasn't be set by
      *             {@link #setExperimentRegistrator(ExperimentRegistrator)}.
      */
-    public ExperimentRegistrator getExperimentRegistrator()
+    public final ExperimentRegistrator getExperimentRegistrator()
     {
         assertOpenOrCreated();
         return ExperimentRegistrator.loadFrom(getMetaDataDirectory());
     }
 
-    public void setExperimentRegistrator(final ExperimentRegistrator registrator)
+    public final void setExperimentRegistrator(final ExperimentRegistrator registrator)
     {
         assert registrator != null : "Unspecified experiment registrator.";
         assertOpenOrCreated();
@@ -222,47 +225,25 @@ public class DataStructureV1_0 extends AbstractDataStructure
     }
 
     /**
-     * Returns the measurement entity.
+     * Returns the sample.
      * 
-     * @throws DataStructureException if the processing type hasn't be loaded nor hasn't be set by
-     *             {@link #setProcessingType(ProcessingType)}.
+     * @throws DataStructureException if the sample hasn't be loaded nor hasn't be set by
+     *             {@link #setSample(Sample)}.
      */
-    public MeasurementEntity getMeasurementEntity()
+    public final Sample getSample()
     {
         assertOpenOrCreated();
-        return MeasurementEntity.loadFrom(getMetaDataDirectory());
+        return Sample.loadFrom(getMetaDataDirectory());
     }
 
     /**
      * Sets the measurement entity. Overwrites an already set or loaded value.
      */
-    public void setMeasurementEntity(final MeasurementEntity entity)
-    {
-        assert entity != null : "Unspecified measurement entity.";
-        assertOpenOrCreated();
-        entity.saveTo(getMetaDataDirectory());
-    }
-
-    /**
-     * Returns the processing type.
-     * 
-     * @throws DataStructureException if the processing type hasn't be loaded nor hasn't be set by
-     *             {@link #setProcessingType(ProcessingType)}.
-     */
-    public ProcessingType getProcessingType()
+    public final void setSample(final Sample sample)
     {
+        assert sample != null : "Unspecified measurement entity.";
         assertOpenOrCreated();
-        return ProcessingType.loadFrom(getMetaDataDirectory());
-    }
-
-    /**
-     * Sets the processing type. Overwrites an already set or loaded value.
-     */
-    public void setProcessingType(final ProcessingType type)
-    {
-        assert type != null : "Unspecified processing type.";
-        assertOpenOrCreated();
-        type.saveTo(getMetaDataDirectory());
+        sample.saveTo(getMetaDataDirectory());
     }
 
     public final void addReference(final Reference reference)
@@ -299,7 +280,7 @@ public class DataStructureV1_0 extends AbstractDataStructure
         {
             throw new DataStructureException("Unspecified experiment identifier.");
         }
-        if (metaDataDirectory.tryGetNode(ExperimentRegistratorDate.FILE_NAME) == null)
+        if (metaDataDirectory.tryGetNode(ExperimentRegistrationTimestamp.FILE_NAME) == null)
         {
             throw new DataStructureException("Unspecified experiment registration date.");
         }
@@ -307,14 +288,10 @@ public class DataStructureV1_0 extends AbstractDataStructure
         {
             throw new DataStructureException("Unspecified experiment registrator.");
         }
-        if (metaDataDirectory.tryGetNode(MeasurementEntity.FOLDER) == null)
+        if (metaDataDirectory.tryGetNode(Sample.FOLDER) == null)
         {
             throw new DataStructureException("Unspecified measurement entity.");
         }
-        if (metaDataDirectory.tryGetNode(ProcessingType.PROCESSING_TYPE) == null)
-        {
-            throw new DataStructureException("Unspecified processing type.");
-        }
         if (annotations != null)
         {
             annotations.assertValid(getFormattedData());
diff --git a/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java b/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java
index d481a403c74a11427dbf00bc56ee6c2d597908c2..21d9891ede79c5978590c29befaaa92f3299bcd2 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java
@@ -20,8 +20,8 @@ import ch.systemsx.cisd.bds.exception.DataStructureException;
 import ch.systemsx.cisd.bds.storage.IDirectory;
 
 /**
- * Identifier of the experiment which corresponds to the data. This is an immutable but extendable value object class.
- * An instance of this class allows unique identification in the database.
+ * Identifier of the experiment which corresponds to the data. This is an immutable but extendable
+ * value object class. An instance of this class allows unique identification in the database.
  * 
  * @author Franz-Josef Elmer
  */
@@ -40,12 +40,12 @@ public class ExperimentIdentifier implements IStorable
      * 
      * @throws DataStructureException if file missing.
      */
-    static ExperimentIdentifier loadFrom(IDirectory directory)
+    final static ExperimentIdentifier loadFrom(final IDirectory directory)
     {
-        IDirectory idFolder = Utilities.getSubDirectory(directory, FOLDER);
-        String groupCode = Utilities.getTrimmedString(idFolder, GROUP_CODE);
-        String projectCode = Utilities.getTrimmedString(idFolder, PROJECT_CODE);
-        String experimentCode = Utilities.getTrimmedString(idFolder, EXPERIMENT_CODE);
+        final IDirectory idFolder = Utilities.getSubDirectory(directory, FOLDER);
+        final String groupCode = Utilities.getTrimmedString(idFolder, GROUP_CODE);
+        final String projectCode = Utilities.getTrimmedString(idFolder, PROJECT_CODE);
+        final String experimentCode = Utilities.getTrimmedString(idFolder, EXPERIMENT_CODE);
         return new ExperimentIdentifier(groupCode, projectCode, experimentCode);
     }
 
@@ -62,21 +62,20 @@ public class ExperimentIdentifier implements IStorable
      * @param projectCode A non-empty string of the project code.
      * @param experimentCode A non-empty string of the experiment code.
      */
-    public ExperimentIdentifier(String groupCode, String projectCode, String experimentCode)
+    public ExperimentIdentifier(final String groupCode, final String projectCode,
+            final String experimentCode)
     {
-        assert groupCode != null && groupCode.length() > 0 : "Undefined group code";
+        assert StringUtils.isEmpty(groupCode) == false : "Undefined group code";
         this.groupCode = groupCode;
-        assert projectCode != null && projectCode.length() > 0 : "Undefined project code";
+        assert StringUtils.isEmpty(projectCode) == false : "Undefined project code";
         this.projectCode = projectCode;
-        assert experimentCode != null && experimentCode.length() > 0 : "Undefined experiment code";
+        assert StringUtils.isEmpty(experimentCode) == false : "Undefined experiment code";
         this.experimentCode = experimentCode;
     }
 
     /**
      * Returns the group code;
      */
-    // TODO 2007-12-03, Tomasz Pylak review: should not we use the term organization as everywhere else instead of
-    // group?
     public final String getGroupCode()
     {
         return groupCode;
@@ -107,14 +106,18 @@ public class ExperimentIdentifier implements IStorable
      */
     public final void saveTo(final IDirectory directory)
     {
-        IDirectory folder = directory.makeDirectory(FOLDER);
+        final IDirectory folder = directory.makeDirectory(FOLDER);
         folder.addKeyValuePair(GROUP_CODE, groupCode);
         folder.addKeyValuePair(PROJECT_CODE, projectCode);
         folder.addKeyValuePair(EXPERIMENT_CODE, experimentCode);
     }
 
+    //
+    // Object
+    //
+
     @Override
-    public boolean equals(Object obj)
+    public final boolean equals(final Object obj)
     {
         if (obj == this)
         {
@@ -124,20 +127,23 @@ public class ExperimentIdentifier implements IStorable
         {
             return false;
         }
-        ExperimentIdentifier id = (ExperimentIdentifier) obj;
+        final ExperimentIdentifier id = (ExperimentIdentifier) obj;
         return id.groupCode.equals(groupCode) && id.projectCode.equals(projectCode)
                 && id.experimentCode.equals(experimentCode);
     }
 
     @Override
-    public int hashCode()
+    public final int hashCode()
     {
-        return (groupCode.hashCode() * 37 + projectCode.hashCode()) * 37
-                + experimentCode.hashCode();
+        int result = 17;
+        result = 37 * result + groupCode.hashCode();
+        result = 37 * result + projectCode.hashCode();
+        result = 37 * result + experimentCode.hashCode();
+        return result;
     }
 
     @Override
-    public String toString()
+    public final String toString()
     {
         return "[group:" + groupCode + ",project:" + projectCode + ",experiment:" + experimentCode
                 + "]";
diff --git a/bds/source/java/ch/systemsx/cisd/bds/ExperimentRegistratorDate.java b/bds/source/java/ch/systemsx/cisd/bds/ExperimentRegistrationTimestamp.java
similarity index 50%
rename from bds/source/java/ch/systemsx/cisd/bds/ExperimentRegistratorDate.java
rename to bds/source/java/ch/systemsx/cisd/bds/ExperimentRegistrationTimestamp.java
index 930ef0eee2ef41628fe619acab58ea520aa497e6..f722f1403e94f6dc5073cf6a4daac5109efdd371 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/ExperimentRegistratorDate.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/ExperimentRegistrationTimestamp.java
@@ -16,35 +16,22 @@
 
 package ch.systemsx.cisd.bds;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.Date;
 
-import ch.systemsx.cisd.bds.exception.DataStructureException;
 import ch.systemsx.cisd.bds.storage.IDirectory;
 
 /**
- * Immutable class which holds the date of registration of an experiment.
+ * Immutable class which holds the timestamp of registration of an experiment.
  * 
  * @author Franz-Josef Elmer
  */
-public final class ExperimentRegistratorDate implements IStorable
+public final class ExperimentRegistrationTimestamp implements IStorable
 {
-    static final String FILE_NAME = "experiment_registration_date";
+    static final String FILE_NAME = "experiment_registration_timestamp";
 
-    private static final SimpleDateFormat DATE_FORMAT =
-            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
-
-    static ExperimentRegistratorDate loadFrom(IDirectory directory)
+    final static ExperimentRegistrationTimestamp loadFrom(final IDirectory directory)
     {
-        String dateAsString = Utilities.getTrimmedString(directory, FILE_NAME);
-        try
-        {
-            return new ExperimentRegistratorDate(DATE_FORMAT.parse(dateAsString));
-        } catch (ParseException ex)
-        {
-            throw new DataStructureException("Couldn't be parsed as a date: " + dateAsString);
-        }
+        return new ExperimentRegistrationTimestamp(Utilities.getDateOrNull(directory, FILE_NAME));
     }
 
     private final Date date;
@@ -52,7 +39,7 @@ public final class ExperimentRegistratorDate implements IStorable
     /**
      * Creates an instance for the specified date.
      */
-    public ExperimentRegistratorDate(Date date)
+    public ExperimentRegistrationTimestamp(final Date date)
     {
         this.date = date;
     }
@@ -72,35 +59,39 @@ public final class ExperimentRegistratorDate implements IStorable
     /**
      * Saves this instance to the specified directory.
      */
-    public final void saveTo(IDirectory directory)
+    public final void saveTo(final IDirectory directory)
     {
-        directory.addKeyValuePair(FILE_NAME, DATE_FORMAT.format(date));
+        directory.addKeyValuePair(FILE_NAME, Constants.DATE_FORMAT.format(date));
     }
 
+    //
+    // Object
+    //
+
     @Override
-    public boolean equals(Object obj)
+    public final boolean equals(final Object obj)
     {
         if (obj == this)
         {
             return true;
         }
-        if (obj instanceof ExperimentRegistratorDate == false)
+        if (obj instanceof ExperimentRegistrationTimestamp == false)
         {
             return false;
         }
-        return ((ExperimentRegistratorDate) obj).getDate().getTime() == date.getTime();
+        return ((ExperimentRegistrationTimestamp) obj).getDate().getTime() == date.getTime();
     }
 
     @Override
-    public int hashCode()
+    public final int hashCode()
     {
         return (int) date.getTime();
     }
 
     @Override
-    public String toString()
+    public final String toString()
     {
-        return DATE_FORMAT.format(date);
+        return Constants.DATE_FORMAT.format(date);
     }
 
 }
diff --git a/bds/source/java/ch/systemsx/cisd/bds/MeasurementEntity.java b/bds/source/java/ch/systemsx/cisd/bds/MeasurementEntity.java
deleted file mode 100644
index 2e6850cec6fcfdaa5705184275ca18f1684b186b..0000000000000000000000000000000000000000
--- a/bds/source/java/ch/systemsx/cisd/bds/MeasurementEntity.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2007 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.bds;
-
-import ch.systemsx.cisd.bds.exception.DataStructureException;
-import ch.systemsx.cisd.bds.storage.IDirectory;
-
-/**
- * Enity of measurement or calculation covered by the data. This is an immutable value object class.
- * 
- * @author Franz-Josef Elmer
- */
-public final class MeasurementEntity implements IStorable
-{
-    static final String FOLDER = "measurement_entity";
-
-    static final String ENTITY_TYPE_DESCRIPTION = "entity_type_description";
-
-    static final String ENTITY_CODE = "entity_code";
-
-    /**
-     * Loads the enity from the specified directory.
-     * 
-     * @throws DataStructureException if file missing.
-     */
-    static MeasurementEntity loadFrom(IDirectory directory)
-    {
-        IDirectory folder = Utilities.getSubDirectory(directory, FOLDER);
-        String entityTypeDescription = Utilities.getTrimmedString(folder, ENTITY_TYPE_DESCRIPTION);
-        String entityCode = Utilities.getTrimmedString(folder, ENTITY_CODE);
-        return new MeasurementEntity(entityCode, entityTypeDescription);
-    }
-
-    private final String entityTypeDescription;
-
-    private final String entityCode;
-
-    /**
-     * Creates an instance for the specified code and type description of the entity
-     * 
-     * @param entityCode A non-empty string of the enitity code.
-     * @param entityTypeDescription A non-empty description of the type of entity.
-     */
-    public MeasurementEntity(String entityCode, String entityTypeDescription)
-    {
-        assert entityTypeDescription != null && entityTypeDescription.length() > 0 : "Undefined entity type description";
-        this.entityTypeDescription = entityTypeDescription;
-        assert entityCode != null && entityCode.length() > 0 : "Undefined entity code";
-        this.entityCode = entityCode;
-    }
-
-    /**
-     * Returns the description of the entity type.
-     */
-    public final String getEntityTypeDescription()
-    {
-        return entityTypeDescription;
-    }
-
-    /**
-     * Returns the entity code.
-     */
-    public final String getEntityCode()
-    {
-        return entityCode;
-    }
-
-    //
-    // IStorable
-    //
-
-    /**
-     * Saves this instance to the specified directory.
-     */
-    public final void saveTo(IDirectory directory)
-    {
-        IDirectory folder = directory.makeDirectory(FOLDER);
-        folder.addKeyValuePair(ENTITY_TYPE_DESCRIPTION, entityTypeDescription);
-        folder.addKeyValuePair(ENTITY_CODE, entityCode);
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (obj == this)
-        {
-            return true;
-        }
-        if (obj instanceof MeasurementEntity == false)
-        {
-            return false;
-        }
-        MeasurementEntity entity = (MeasurementEntity) obj;
-        return entity.entityTypeDescription.equals(entityTypeDescription)
-                && entity.entityCode.equals(entityCode);
-    }
-
-    @Override
-    public int hashCode()
-    {
-        return entityTypeDescription.hashCode() * 37 + entityCode.hashCode();
-    }
-
-    @Override
-    public String toString()
-    {
-        return "[" + entityCode + ": " + entityTypeDescription + "]";
-    }
-
-}
diff --git a/bds/source/java/ch/systemsx/cisd/bds/ObservableType.java b/bds/source/java/ch/systemsx/cisd/bds/ObservableType.java
new file mode 100644
index 0000000000000000000000000000000000000000..803d000d41d16a40baa2a1b52319d563db155457
--- /dev/null
+++ b/bds/source/java/ch/systemsx/cisd/bds/ObservableType.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 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.bds;
+
+/**
+ * The current <code>ObservableType</code> codes.
+ * 
+ * @author Christian Ribeaud
+ */
+public enum ObservableType
+{
+    HCS_IMAGE("HCS_IMAGE"), HCS_IMAGE_ANALYSIS_DATA("HCS_IMAGE_ANALYSIS_DATA"), UNKNOWN("UNKNOWN");
+
+    private final String code;
+
+    private ObservableType(final String code)
+    {
+        this.code = code;
+    }
+
+    /**
+     * Returns the code of this observable type.
+     */
+    public final String getCode()
+    {
+        return code;
+    }
+
+    /** For given <var>typeCode</var> returns the corresponding {@link ObservableType}. */
+    public final static ObservableType getObservableTypeCode(final String typeCode)
+    {
+        assert typeCode != null : "Unspecified observable type code.";
+        for (final ObservableType observableTypeCode : values())
+        {
+            if (observableTypeCode.code.equals(typeCode))
+            {
+                return observableTypeCode;
+            }
+        }
+        throw new IllegalArgumentException(String.format(
+                "No observable type for given code '%s' found.", typeCode));
+    }
+
+}
diff --git a/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java b/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java
deleted file mode 100644
index 94d4c25419e817f350ebaa014eaef932d7633f38..0000000000000000000000000000000000000000
--- a/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2007 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.bds;
-
-import ch.systemsx.cisd.bds.storage.IDirectory;
-
-/**
- * Enumeration of processing types.
- * 
- * @author Franz-Josef Elmer
- */
-public enum ProcessingType implements IStorable
-{
-    OTHER, RAW_DATA, COMPUTED_DATA;
-
-    static final String PROCESSING_TYPE = "processing_type";
-
-    /**
-     * Resolves the specified string representation of a processing type.
-     * 
-     * @return {@link #OTHER} if <code>processingTypeString</code> is unknown.
-     */
-    public static ProcessingType resolve(String processingTypeString)
-    {
-        ProcessingType[] values = values();
-        for (ProcessingType type : values)
-        {
-            if (type.toString().equals(processingTypeString))
-            {
-                return type;
-            }
-        }
-        return OTHER;
-    }
-
-    static ProcessingType loadFrom(IDirectory directory)
-    {
-        return resolve(Utilities.getTrimmedString(directory, PROCESSING_TYPE));
-    }
-
-    //
-    // IStorable
-    //
-
-    public final void saveTo(IDirectory directory)
-    {
-        directory.addKeyValuePair(PROCESSING_TYPE, toString());
-    }
-}
diff --git a/bds/source/java/ch/systemsx/cisd/bds/Sample.java b/bds/source/java/ch/systemsx/cisd/bds/Sample.java
new file mode 100644
index 0000000000000000000000000000000000000000..0383597ee450147ce8b2785277b0702dae8f599d
--- /dev/null
+++ b/bds/source/java/ch/systemsx/cisd/bds/Sample.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2007 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.bds;
+
+import ch.systemsx.cisd.bds.exception.DataStructureException;
+import ch.systemsx.cisd.bds.storage.IDirectory;
+
+/**
+ * Enity of measurement or calculation covered by the data. This is an immutable value object class.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public final class Sample implements IStorable
+{
+    static final String FOLDER = "sample";
+
+    static final String SAMPLE_TYPE_DESCRIPTION = "sample_type_description";
+
+    static final String SAMPLE_TYPE_CODE = "sample_type_code";
+
+    static final String SAMPLE_CODE = "sample_code";
+
+    /**
+     * Loads the enity from the specified directory.
+     * 
+     * @throws DataStructureException if file missing.
+     */
+    final static Sample loadFrom(final IDirectory directory)
+    {
+        final IDirectory folder = Utilities.getSubDirectory(directory, FOLDER);
+        final String sampleTypeDescription =
+                Utilities.getTrimmedString(folder, SAMPLE_TYPE_DESCRIPTION);
+        final String sampleCode = Utilities.getTrimmedString(folder, SAMPLE_CODE);
+        SampleType sampleType = null;
+        try
+        {
+            sampleType =
+                    SampleType.getSampleTypeCode(Utilities.getTrimmedString(folder,
+                            SAMPLE_TYPE_CODE));
+        } catch (final IllegalArgumentException ex)
+        {
+            throw new DataStructureException(ex.getMessage());
+        }
+        return new Sample(sampleCode, sampleType, sampleTypeDescription);
+    }
+
+    private final String typeDescription;
+
+    private final SampleType type;
+
+    private final String sampleCode;
+
+    /**
+     * Creates an instance for the specified code and type description of the sample.
+     * 
+     * @param sampleCode A non-empty string of the sample code.
+     * @param sampleType the sample type code.
+     * @param sampleTypeDescription A non-empty description of the sample type.
+     */
+    public Sample(final String sampleCode, final SampleType sampleType,
+            final String sampleTypeDescription)
+    {
+        assert StringUtils.isEmpty(sampleTypeDescription) == false : "Undefined sample type description.";
+        this.typeDescription = sampleTypeDescription;
+        assert StringUtils.isEmpty(sampleCode) == false : "Undefined sample code.";
+        this.sampleCode = sampleCode;
+        assert sampleType != null : "Undefined sample type code.";
+        this.type = sampleType;
+    }
+
+    /**
+     * Returns the description of the sample type.
+     */
+    public final String getTypeDescription()
+    {
+        return typeDescription;
+    }
+
+    /**
+     * Returns the sample type.
+     */
+    public final SampleType getType()
+    {
+        return type;
+    }
+
+    /**
+     * Returns the sample code.
+     */
+    public final String getSampleCode()
+    {
+        return sampleCode;
+    }
+
+    //
+    // IStorable
+    //
+
+    /**
+     * Saves this instance to the specified directory.
+     */
+    public final void saveTo(final IDirectory directory)
+    {
+        final IDirectory folder = directory.makeDirectory(FOLDER);
+        folder.addKeyValuePair(SAMPLE_TYPE_DESCRIPTION, typeDescription);
+        folder.addKeyValuePair(SAMPLE_CODE, sampleCode);
+        folder.addKeyValuePair(SAMPLE_TYPE_CODE, type.getCode());
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public final boolean equals(final Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+        if (obj instanceof Sample == false)
+        {
+            return false;
+        }
+        final Sample that = (Sample) obj;
+        return that.sampleCode.equals(sampleCode) && type == that.type;
+    }
+
+    @Override
+    public final int hashCode()
+    {
+        int result = 17;
+        result = 37 * result + sampleCode.hashCode();
+        result = 37 * result + type.hashCode();
+        return result;
+    }
+
+    @Override
+    public final String toString()
+    {
+        return "[code:" + sampleCode + ",type:" + type + ",typeDescription:"
+                + typeDescription + "]";
+    }
+
+}
diff --git a/bds/source/java/ch/systemsx/cisd/bds/SampleType.java b/bds/source/java/ch/systemsx/cisd/bds/SampleType.java
new file mode 100644
index 0000000000000000000000000000000000000000..685422dfca8968ee4ea850cb11dc9070c84ced17
--- /dev/null
+++ b/bds/source/java/ch/systemsx/cisd/bds/SampleType.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2007 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.bds;
+
+/**
+ * The current <code>SampleType</code> codes.
+ * 
+ * @author Christian Ribeaud
+ */
+public enum SampleType
+{
+    CELL_PLATE("CELL_PLATE"), REINFECTION_PLATE("REINFECT_PLATE");
+
+    private final String code;
+
+    private SampleType(final String code)
+    {
+        this.code = code;
+    }
+
+    public final String getCode()
+    {
+        return code;
+    }
+
+    /** For given <var>typeCode</var> returns the corresponding <code>SampleTypeCode</code>. */
+    public final static SampleType getSampleTypeCode(final String typeCode)
+    {
+        assert typeCode != null;
+        for (final SampleType sampleTypeCode : values())
+        {
+            if (sampleTypeCode.code.equals(typeCode))
+            {
+                return sampleTypeCode;
+            }
+        }
+        throw new IllegalArgumentException(String.format(
+                "No sample type for given code '%s' found.", typeCode));
+    }
+}
\ No newline at end of file
diff --git a/bds/source/java/ch/systemsx/cisd/bds/StringUtils.java b/bds/source/java/ch/systemsx/cisd/bds/StringUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e6d79a290c6c1d4e968335195da789bcb7a86f9
--- /dev/null
+++ b/bds/source/java/ch/systemsx/cisd/bds/StringUtils.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2007 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.bds;
+
+/**
+ * Operations on {@link java.lang.String} that are <code>null</code> safe.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class StringUtils
+{
+    public static final String EMPTY_STRING = "";
+
+    private StringUtils()
+    {
+        // Can not be instantiated
+    }
+
+    /**
+     * Whether given <var>value</var> is blank or not.
+     */
+    public final static boolean isBlank(final String value)
+    {
+        return value == null || value.trim().length() == 0;
+    }
+
+    /**
+     * Whether given <var>value</var> is empty or not.
+     */
+    public final static boolean isEmpty(final String value)
+    {
+        return value == null || value.length() == 0;
+    }
+
+    /** Returns an empty if given <var>stringOrNull</var> is <code>null</code>. */
+    public final static String emptyIfNull(final String stringOrNull)
+    {
+        return stringOrNull == null ? EMPTY_STRING : stringOrNull;
+    }
+}
diff --git a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java
index cba6cc60b49135d54a33517713fa6def8454d288..eead0e4fdfc990000103da9fa04f04aa24613603 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.bds;
 
+import java.text.ParseException;
+import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -36,11 +38,12 @@ public class Utilities
     /**
      * Returns a subdirectory from the specified directory. If it does not exist it will be created.
      * 
-     * @throws DataStructureException if there is already a node named <code>name</code> but which isn't a directory.
+     * @throws DataStructureException if there is already a node named <code>name</code> but which
+     *             isn't a directory.
      */
-    public static IDirectory getOrCreateSubDirectory(IDirectory directory, String name)
+    public static IDirectory getOrCreateSubDirectory(final IDirectory directory, final String name)
     {
-        INode node = directory.tryGetNode(name);
+        final INode node = directory.tryGetNode(name);
         if (node == null)
         {
             return directory.makeDirectory(name);
@@ -63,7 +66,7 @@ public class Utilities
     public final static IDirectory getSubDirectory(final IDirectory directory, final String name)
             throws DataStructureException
     {
-        INode node = directory.tryGetNode(name);
+        final INode node = directory.tryGetNode(name);
         if (node == null)
         {
             throw new DataStructureException(String.format(
@@ -79,7 +82,7 @@ public class Utilities
     /**
      * Convenient short cut for <code>{@link #getString(IDirectory, String)}.trim()</code>.
      */
-    public static String getTrimmedString(IDirectory directory, String name)
+    public static String getTrimmedString(final IDirectory directory, final String name)
     {
         return getString(directory, name).trim();
     }
@@ -89,6 +92,7 @@ public class Utilities
      * 
      * @param directory Directory of the requested file.
      * @param name Name of the file.
+     * @return never <code>null</code> but could return an empty string.
      * @throws DataStructureException if the requested file does not exist.
      */
     public static String getString(final IDirectory directory, final String name)
@@ -99,10 +103,12 @@ public class Utilities
     }
 
     /**
-     * Returns the string content of a file from the specified directory as list of <code>String</code> objects.
+     * Returns the string content of a file from the specified directory as list of
+     * <code>String</code> objects.
      * 
      * @param directory Directory of the requested file.
      * @param name Name of the file.
+     * @return never <code>null</code> but could return an empty list.
      * @throws DataStructureException if the requested file does not exist.
      */
     public static List<String> getStringList(final IDirectory directory, final String name)
@@ -132,21 +138,65 @@ public class Utilities
     {
     }
 
+    /**
+     * Return the string content of a file from the given <var>directory</var> as boolean (<code>TRUE</code>
+     * or <code>FALSE</code>).
+     */
+    public static boolean getBoolean(final IDirectory directory, final String name)
+            throws DataStructureException
+    {
+        // No assertion here as 'getString(IDirectory, String)' already does it.
+        final String value = getTrimmedString(directory, name);
+        try
+        {
+            return Boolean.valueOf(value).toBoolean();
+        } catch (final IllegalArgumentException ex)
+        {
+            throw new DataStructureException("Value of '" + name
+                    + "' version file is not a boolean (TRUE or FALSE): " + value);
+        }
+    }
+
     /** For given <code>IDirectory</code> returns the number value corresponding to given <var>name</var>. */
     public final static int getNumber(final IDirectory directory, final String name)
+            throws DataStructureException
     {
         // No assertion here as 'getString(IDirectory, String)' already does it.
         final String value = getTrimmedString(directory, name);
         try
         {
             return Integer.parseInt(value);
-        } catch (NumberFormatException ex)
+        } catch (final NumberFormatException ex)
         {
             throw new DataStructureException("Value of '" + name
                     + "' version file is not a number: " + value);
         }
     }
 
+    /**
+     * For given <code>IDirectory</code> returns the date value corresponding to given <var>name</var>.
+     * 
+     * @return the parsed date or <code>null</code> if the value is empty.
+     */
+    public final static Date getDateOrNull(final IDirectory directory, final String name)
+            throws DataStructureException
+    {
+        // No assertion here as 'getString(IDirectory, String)' already does it.
+        final String value = getTrimmedString(directory, name);
+        if (StringUtils.isEmpty(value))
+        {
+            return null;
+        }
+        try
+        {
+            return Constants.DATE_FORMAT.parse(value);
+        } catch (final ParseException ex)
+        {
+            throw new DataStructureException("Value of '" + name + "' version file is not a date: "
+                    + value);
+        }
+    }
+
     /**
      * Recursively lists nodes in given <var>directory</var>.
      */
@@ -183,4 +233,22 @@ public class Utilities
             }
         }
     }
+
+    //
+    // Helper classes
+    //
+
+    /**
+     * A boolean object that only accepts <code>TRUE</code> or <code>FALSE</code> as value
+     * (case-sensitive).
+     */
+    private static enum Boolean
+    {
+        TRUE, FALSE;
+
+        final boolean toBoolean()
+        {
+            return this == TRUE ? true : false;
+        }
+    }
 }
\ No newline at end of file
diff --git a/bds/source/java/ch/systemsx/cisd/bds/hcs/HCSImageAnnotations.java b/bds/source/java/ch/systemsx/cisd/bds/hcs/HCSImageAnnotations.java
index 9095a07fb817d84c221d5a99c1eb9814967fe162..ff96ebd44243d6acff828a17b72bc2ba8513d9e9 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/hcs/HCSImageAnnotations.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/hcs/HCSImageAnnotations.java
@@ -34,36 +34,23 @@ import ch.systemsx.cisd.bds.storage.IDirectory;
  */
 public final class HCSImageAnnotations implements IAnnotations
 {
-    private static final String DEVICE_ID = "device_id";
-
     private static final Set<Format> FORMATS =
             Collections.unmodifiableSet(new HashSet<Format>(Arrays
                     .asList(HCSImageFormatV1_0.HCS_IMAGE_1_0)));
 
-    private Set<Channel> channels;
-
-    private String deviceID;
-
-    public final String getDeviceID()
-    {
-        return deviceID;
-    }
+    private final Set<Channel> channels;
 
-    public final void setDeviceID(final String deviceID)
+    public HCSImageAnnotations(final Set<Channel> channels)
     {
-        this.deviceID = deviceID;
+        this.channels = channels;
     }
 
+    /** Returns an unmodifiable set of <code>Channels</code>. */
     public final Set<Channel> getChannels()
     {
         return Collections.unmodifiableSet(channels);
     }
 
-    public final void setChannels(final Set<Channel> channels)
-    {
-        this.channels = channels;
-    }
-
     //
     // IAnnotations
     //
@@ -89,10 +76,6 @@ public final class HCSImageAnnotations implements IAnnotations
 
     public final void saveTo(final IDirectory directory)
     {
-        if (deviceID != null)
-        {
-            directory.addKeyValuePair(DEVICE_ID, deviceID);
-        }
         for (final Channel channel : channels)
         {
             channel.saveTo(directory);
diff --git a/bds/source/java/ch/systemsx/cisd/bds/package.html b/bds/source/java/ch/systemsx/cisd/bds/package.html
index 63a8de75573cbbf60f1f00dc909072e1a367b3d4..1905713742f34015cf7b76f3867c5dd2ff99b77b 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/package.html
+++ b/bds/source/java/ch/systemsx/cisd/bds/package.html
@@ -13,7 +13,6 @@ storage.mount();
 DataStructureV1_0 dataStructure = new DataStructureV1_0(storage);
 dataStructure.getOriginalData().addFile(someFileWithData);
 dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0);
-dataStructure.setProcessingType(ProcessingType.RAW_DATA);
 dataStructure.setExperimentIdentifier(new ExperimentIdentifier("myGroup", "My project", "exp1"));
 dataStructure.save();
 storage.unmount();
diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java b/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java
index 4deac1f415b1bd54d23935515cf953de4cd5403b..62b8e9c4113ddf4e9e45ce83275a1b7baae7cfe6 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java
@@ -41,17 +41,20 @@ public interface IDirectory extends INode, Iterable<INode>
     public IDirectory makeDirectory(final String name);
 
     /**
-     * Adds the specified real file to this directory. The content of <code>file</code> will be copied. If it is a
-     * folder also its complete content including all subfolders will be copied.
+     * Adds the specified real file to this directory. The content of <code>file</code> will be
+     * copied. If it is a folder also its complete content including all subfolders will be copied.
      * 
-     * @param nameOrNull the name of the returned node. If <code>null</code>, then given <var>file</var> name is
-     *            taken.
+     * @param nameOrNull the name of the returned node. If <code>null</code>, then given
+     *            <var>file</var> name is taken.
      * @param move whether given <var>file</var> should be copied or moved.
-     * @return the new node. It will be a {@link ILink} if <code>file</code> is a symbolic link, a {@link IDirectory}
-     *         if <code>file</code> is a folder, or {@link IFile} if <code>file</code> is a plain file.
+     * @return the new node. It will be a {@link ILink} if <code>file</code> is a symbolic link, a
+     *         {@link IDirectory} if <code>file</code> is a folder, or {@link IFile} if
+     *         <code>file</code> is a plain file.
      */
-    // TODO 2007-12-03, Tomasz Pylak review: this generic interface should not use java.io.File. Is the 'move' parameter
-    // possible to implement in HDF5? Maybe those operations should be done before, depending on the implementation
+    // TODO 2007-12-03, Tomasz Pylak review: this generic interface should not use java.io.File. Is
+    // the 'move' parameter
+    // possible to implement in HDF5? Maybe those operations should be done before, depending on the
+    // implementation
     // which is used?
     public INode addFile(final File file, final String nameOrNull, final boolean move);
 
@@ -61,7 +64,12 @@ public interface IDirectory extends INode, Iterable<INode>
     public void removeNode(final INode node);
 
     /**
-     * Adds a plain file named <code>key</code> with content <code>value</code> to this directory.
+     * Adds a plain file named <code>key</code> with content <code>value</code> to this
+     * directory.
+     * 
+     * @param key key (or file name) that stores given <var>value</var>. Can not be
+     *            <code>null</code>.
+     * @param value value of this pair. Can not be <code>null</code>.
      */
     public IFile addKeyValuePair(final String key, final String value);
 
diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java b/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java
index 05bbdcb129e6bc15e38ed3e94536a16f2e674039..0f28c6016d314805beab951f3fba9a430b468e71 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java
@@ -28,6 +28,8 @@ public interface IFile extends INode
 {
     /**
      * Returns the content of this file node as a byte array.
+     * 
+     * @return never <code>null</code> but could return an empty byte array.
      */
     public byte[] getBinaryContent();
 
@@ -38,6 +40,8 @@ public interface IFile extends INode
 
     /**
      * Returns the content of this file node as a string.
+     * 
+     * @return never <code>null</code> but could return an empty string.
      */
     public String getStringContent();
 
@@ -46,6 +50,8 @@ public interface IFile extends INode
      * <p>
      * This is useful when you know that the file content is composed of several lines.
      * </p>
+     * 
+     * @return never <code>null</code> but could return an empty list.
      */
     public List<String> getStringContentList();
 
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataSetTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataSetTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf5d31d2b549a6487fdf39113f1e9628ba1c514c
--- /dev/null
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataSetTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 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.bds;
+
+import ch.systemsx.cisd.common.test.EqualsHashCodeTestCase;
+
+/**
+ * Test cases for corresponding {@link DataSet} class.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class DataSetTest extends EqualsHashCodeTestCase<DataSet>
+{
+
+    //
+    // EqualsHashCodeTestCase
+    //
+
+    @Override
+    protected final DataSet createInstance() throws Exception
+    {
+        return new DataSet("code", ObservableType.HCS_IMAGE, true, null, null, null);
+    }
+
+    @Override
+    protected final DataSet createNotEqualInstance() throws Exception
+    {
+        return new DataSet("code1", ObservableType.HCS_IMAGE, true, null, null, null);
+    }
+
+}
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java
index d22ac7c21b1b5d00e00ffe248ae09e1fb642a7ea..7589dade5add5fa9d83648d95c57be74a2c78204 100644
--- a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java
@@ -37,23 +37,23 @@ public final class DataStructureLoaderTest extends AbstractFileSystemTestCase
     @Test
     public final void testOpen()
     {
-        File dir = new File(workingDirectory, "ds");
+        final File dir = new File(workingDirectory, "ds");
         assert dir.mkdir();
-        DataStructureV1_0 dataStructure = new DataStructureV1_0(new FileStorage(dir));
+        final DataStructureV1_0 dataStructure = new DataStructureV1_0(new FileStorage(dir));
         dataStructure.create();
         dataStructure.getOriginalData().addKeyValuePair("answer", "42");
         dataStructure.setFormat(UnknownFormatV1_0.UNKNOWN_1_0);
-        ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("g", "p", "e");
+        final ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(experimentIdentifier);
-        ExperimentRegistrator experimentRegistrator =
+        final ExperimentRegistrator experimentRegistrator =
                 new ExperimentRegistrator("john", "doe", "j@doe");
         dataStructure.setExperimentRegistrator(experimentRegistrator);
-        dataStructure.setExperimentRegistrationDate(new ExperimentRegistratorDate(new Date(0)));
-        dataStructure.setMeasurementEntity(new MeasurementEntity("a", "b"));
-        dataStructure.setProcessingType(ProcessingType.RAW_DATA);
+        dataStructure.setExperimentRegistrationTimestamp(new ExperimentRegistrationTimestamp(
+                new Date(0)));
+        dataStructure.setSample(new Sample("a", SampleType.CELL_PLATE, "b"));
         dataStructure.close();
 
-        IDataStructure ds = new DataStructureLoader(workingDirectory).load("ds");
+        final IDataStructure ds = new DataStructureLoader(workingDirectory).load("ds");
         assertEquals(DataStructureV1_0.class, ds.getClass());
         assertEquals(experimentIdentifier, ((DataStructureV1_0) ds).getExperimentIdentifier());
     }
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureTestV1_0.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureTestV1_0.java
index 87a0b7916b15e8fbf5c54d8e499213d60a4d1893..fa31a21681a90c29e4ee42947dae5fdaddf24213 100644
--- a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureTestV1_0.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureTestV1_0.java
@@ -46,7 +46,7 @@ import ch.systemsx.cisd.common.utilities.AbstractFileSystemTestCase;
  */
 public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
 {
-    private static void assertPartOfString(String part, String string)
+    private static void assertPartOfString(final String part, final String string)
     {
         assertTrue("Expected <" + part + "> is part of <" + string + ">", string.indexOf(part) >= 0);
     }
@@ -72,7 +72,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     public void testGetOriginalData()
     {
         dataStructure.create();
-        IDirectory dataFolder = dataStructure.getOriginalData();
+        final IDirectory dataFolder = dataStructure.getOriginalData();
         assertEquals(DataStructureV1_0.DIR_ORIGINAL, dataFolder.getName());
         assertEquals(DataStructureV1_0.DIR_DATA, dataFolder.tryToGetParent().getName());
     }
@@ -82,7 +82,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     {
         dataStructure.create();
         dataStructure.setFormat(UnknownFormatV1_0.UNKNOWN_1_0);
-        IFormattedData formattedData = dataStructure.getFormattedData();
+        final IFormattedData formattedData = dataStructure.getFormattedData();
         assertTrue(formattedData instanceof NoFormattedData);
         assertEquals(UnknownFormatV1_0.UNKNOWN_1_0, formattedData.getFormat());
     }
@@ -95,63 +95,22 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         {
             dataStructure.getFormattedData();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals("Couldn't create formatted data because of unspecified format.", e
                     .getMessage());
         }
     }
 
-    @Test
-    public void testSetProcessingType()
-    {
-        dataStructure.create();
-        dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA);
-        IDirectory root = storage.getRoot();
-        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
-        assertEquals("COMPUTED_DATA\n", Utilities.getString(metaData,
-                ProcessingType.PROCESSING_TYPE));
-    }
-
-    @Test
-    public void testSetProcessingTypeTwice()
-    {
-        dataStructure.create();
-        dataStructure.setProcessingType(ProcessingType.RAW_DATA);
-        dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA);
-        IDirectory root = storage.getRoot();
-        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
-        assertEquals("COMPUTED_DATA\n", Utilities.getString(metaData,
-                ProcessingType.PROCESSING_TYPE));
-    }
-
-    @Test
-    public void testGetProcessingType()
-    {
-        dataStructure.create();
-        dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA);
-        assertEquals(ProcessingType.COMPUTED_DATA, dataStructure.getProcessingType());
-    }
-
-    @Test
-    public void testGetUnknownProcessingType()
-    {
-        dataStructure.create();
-        dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA);
-        IDirectory s = Utilities.getSubDirectory(storage.getRoot(), DataStructureV1_0.DIR_METADATA);
-        s.addKeyValuePair(ProcessingType.PROCESSING_TYPE, "blabla");
-        assertEquals(ProcessingType.OTHER, dataStructure.getProcessingType());
-    }
-
     @Test
     public void testSetExperimentIdentifier()
     {
         dataStructure.create();
-        ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
+        final ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(id);
-        IDirectory root = storage.getRoot();
-        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
-        IDirectory idDir = Utilities.getSubDirectory(metaData, ExperimentIdentifier.FOLDER);
+        final IDirectory root = storage.getRoot();
+        final IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
+        final IDirectory idDir = Utilities.getSubDirectory(metaData, ExperimentIdentifier.FOLDER);
         assertEquals("g\n", Utilities.getString(idDir, ExperimentIdentifier.GROUP_CODE));
         assertEquals("p\n", Utilities.getString(idDir, ExperimentIdentifier.PROJECT_CODE));
         assertEquals("e\n", Utilities.getString(idDir, ExperimentIdentifier.EXPERIMENT_CODE));
@@ -162,11 +121,11 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     {
         dataStructure.create();
         dataStructure.setExperimentIdentifier(new ExperimentIdentifier("a", "b", "c"));
-        ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
+        final ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(id);
-        IDirectory root = storage.getRoot();
-        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
-        IDirectory idDir = Utilities.getSubDirectory(metaData, ExperimentIdentifier.FOLDER);
+        final IDirectory root = storage.getRoot();
+        final IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
+        final IDirectory idDir = Utilities.getSubDirectory(metaData, ExperimentIdentifier.FOLDER);
         assertEquals("g\n", Utilities.getString(idDir, ExperimentIdentifier.GROUP_CODE));
         assertEquals("p\n", Utilities.getString(idDir, ExperimentIdentifier.PROJECT_CODE));
         assertEquals("e\n", Utilities.getString(idDir, ExperimentIdentifier.EXPERIMENT_CODE));
@@ -180,7 +139,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         {
             dataStructure.getExperimentIdentifier();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertPartOfString(ExperimentIdentifier.FOLDER, e.getMessage());
         }
@@ -190,7 +149,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     public void testGetExperimentIdentifier()
     {
         dataStructure.create();
-        ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
+        final ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(id);
         assertEquals(id, dataStructure.getExperimentIdentifier());
     }
@@ -224,7 +183,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         {
             dataStructure.addReference(new Reference("a", "b", ReferenceType.IDENTICAL));
             fail("DataStructureException expected");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals("There is already a reference for file 'a'.", e.getMessage());
         }
@@ -238,7 +197,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         {
             dataStructure.getStandardOriginalMapping().add(null);
             fail("DataStructureException expected");
-        } catch (UnsupportedOperationException e)
+        } catch (final UnsupportedOperationException e)
         {
             // ignored
         }
@@ -253,7 +212,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         {
             dataStructure.close();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals("Unspecified format.", e.getMessage());
         }
@@ -269,7 +228,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         {
             dataStructure.close();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals("Unspecified experiment identifier.", e.getMessage());
         }
@@ -282,12 +241,13 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         dataStructure.getOriginalData().addKeyValuePair("answer", "42");
         dataStructure.setFormat(UnknownFormatV1_0.UNKNOWN_1_0);
         dataStructure.setExperimentIdentifier(new ExperimentIdentifier("g", "p", "e"));
-        dataStructure.setExperimentRegistrationDate(new ExperimentRegistratorDate(new Date(0)));
+        dataStructure.setExperimentRegistrationTimestamp(new ExperimentRegistrationTimestamp(
+                new Date(0)));
         try
         {
             dataStructure.close();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals("Unspecified experiment registrator.", e.getMessage());
         }
@@ -305,7 +265,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         {
             dataStructure.close();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals("Unspecified experiment registration date.", e.getMessage());
         }
@@ -319,87 +279,66 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         dataStructure.setFormat(UnknownFormatV1_0.UNKNOWN_1_0);
         dataStructure.setExperimentIdentifier(new ExperimentIdentifier("g", "p", "e"));
         dataStructure.setExperimentRegistrator(new ExperimentRegistrator("g", "p", "g@p"));
-        dataStructure.setExperimentRegistrationDate(new ExperimentRegistratorDate(new Date(0)));
+        dataStructure.setExperimentRegistrationTimestamp(new ExperimentRegistrationTimestamp(
+                new Date(0)));
         try
         {
             dataStructure.close();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals("Unspecified measurement entity.", e.getMessage());
         }
     }
 
-    @Test
-    public void testCloseIfNoProcessingType()
-    {
-        dataStructure.create();
-        dataStructure.getOriginalData().addKeyValuePair("answer", "42");
-        dataStructure.setFormat(UnknownFormatV1_0.UNKNOWN_1_0);
-        dataStructure.setExperimentIdentifier(new ExperimentIdentifier("g", "p", "e"));
-        dataStructure.setExperimentRegistrator(new ExperimentRegistrator("g", "p", "g@p"));
-        dataStructure.setExperimentRegistrationDate(new ExperimentRegistratorDate(new Date(0)));
-        dataStructure.setMeasurementEntity(new MeasurementEntity("a", "b"));
-        try
-        {
-            dataStructure.close();
-            fail("DataStructureException expected.");
-        } catch (DataStructureException e)
-        {
-            assertEquals("Unspecified processing type.", e.getMessage());
-        }
-    }
-
     @Test
     public void testClose()
     {
         dataStructure.create();
         dataStructure.getOriginalData().addKeyValuePair("answer", "42");
         dataStructure.setFormat(UnknownFormatV1_0.UNKNOWN_1_0);
-        ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("g", "p", "e");
+        final ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(experimentIdentifier);
-        ExperimentRegistratorDate experimentRegistratorDate =
-                new ExperimentRegistratorDate(new Date(4711L * 4711000L));
+        final ExperimentRegistrationTimestamp experimentRegistratorDate =
+                new ExperimentRegistrationTimestamp(new Date(4711L * 4711000L));
         System.out.println(experimentRegistratorDate);
-        dataStructure.setExperimentRegistrationDate(experimentRegistratorDate);
-        ExperimentRegistrator experimentRegistrator =
+        dataStructure.setExperimentRegistrationTimestamp(experimentRegistratorDate);
+        final ExperimentRegistrator experimentRegistrator =
                 new ExperimentRegistrator("john", "doe", "j@doe");
         dataStructure.setExperimentRegistrator(experimentRegistrator);
-        MeasurementEntity measurementEntity = new MeasurementEntity("cp001", "plate");
-        dataStructure.setMeasurementEntity(measurementEntity);
-        dataStructure.setProcessingType(ProcessingType.RAW_DATA);
+        final Sample sample = new Sample("cp001", SampleType.CELL_PLATE, "plate");
+        dataStructure.setSample(sample);
         addReference("path1", "origFile1", ReferenceType.IDENTICAL);
         addReference("path2", "origFile2", ReferenceType.TRANSFORMED);
         dataStructure.addFormatParameter(new FormatParameter("plate_dimension", "16x24"));
         checkFormattedData(dataStructure.getFormattedData());
 
-        IDirectory root = storage.getRoot();
+        final IDirectory root = storage.getRoot();
         dataStructure.close();
         assertEquals(dataStructure.getVersion(), Version.loadFrom(root));
         try
         {
             storage.getRoot();
             fail("StorageException expected because save() should unmount storage.");
-        } catch (StorageException e)
+        } catch (final StorageException e)
         {
             assertEquals("Can not get root of an unmounted storage.", e.getMessage());
         }
 
-        DataStructureV1_0 reloadedDataStructure = new DataStructureV1_0(storage);
+        final DataStructureV1_0 reloadedDataStructure = new DataStructureV1_0(storage);
         reloadedDataStructure.open();
         assertEquals("42\n", Utilities.getString(reloadedDataStructure.getOriginalData(), "answer"));
         assertEquals(experimentIdentifier, reloadedDataStructure.getExperimentIdentifier());
         assertEquals(experimentRegistratorDate, reloadedDataStructure
-                .getExperimentRegistratorDate());
+                .getExperimentRegistratorTimestamp());
         assertEquals(experimentRegistrator, reloadedDataStructure.getExperimentRegistrator());
-        assertEquals(measurementEntity, reloadedDataStructure.getMeasurementEntity());
-        assertEquals(ProcessingType.RAW_DATA, reloadedDataStructure.getProcessingType());
+        assertEquals(sample, reloadedDataStructure.getSample());
         final Set<Reference> mapping = reloadedDataStructure.getStandardOriginalMapping();
         assertEquals(2, mapping.size());
         checkFormattedData(reloadedDataStructure.getFormattedData());
 
-        IDirectory metaDataDir = Utilities.getSubDirectory(root, DIR_METADATA);
-        IDirectory checksumDir =
+        final IDirectory metaDataDir = Utilities.getSubDirectory(root, DIR_METADATA);
+        final IDirectory checksumDir =
                 Utilities.getSubDirectory(metaDataDir, ChecksumHandler.CHECKSUM_DIRECTORY);
         assertEquals("a1d0c6e83f027327d8461063f4ac58a6  answer\n"
                 + "d41d8cd98f00b204e9800998ecf8427e  origFile1\n"
@@ -407,20 +346,21 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
                 DataStructureV1_0.DIR_ORIGINAL));
     }
 
-    private final void addReference(final String path, final String originalPath, ReferenceType type)
+    private final void addReference(final String path, final String originalPath,
+            final ReferenceType type)
     {
         dataStructure.getOriginalData().addKeyValuePair(originalPath, "");
         dataStructure.getStandardData().addKeyValuePair(path, "");
         dataStructure.addReference(new Reference(path, originalPath, type));
     }
 
-    private void checkFormattedData(IFormattedData formattedData)
+    private void checkFormattedData(final IFormattedData formattedData)
     {
         assertEquals(UnknownFormatV1_0.UNKNOWN_1_0, formattedData.getFormat());
-        IFormatParameters formatParameters = formattedData.getFormatParameters();
-        Iterator<FormatParameter> iterator = formatParameters.iterator();
+        final IFormatParameters formatParameters = formattedData.getFormatParameters();
+        final Iterator<FormatParameter> iterator = formatParameters.iterator();
         assertTrue(iterator.hasNext());
-        FormatParameter parameter = iterator.next();
+        final FormatParameter parameter = iterator.next();
         assertEquals("plate_dimension", parameter.getName());
         assertEquals("16x24", parameter.getValue());
         assertFalse(iterator.hasNext());
@@ -431,14 +371,14 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     {
         createExampleDataStructure();
         storage.mount();
-        IDirectory root = storage.getRoot();
+        final IDirectory root = storage.getRoot();
         root.removeNode(Utilities.getSubDirectory(root, Version.VERSION));
         storage.unmount();
         try
         {
             dataStructure.open();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertPartOfString(Version.VERSION, e.getMessage());
         }
@@ -456,7 +396,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     {
         createExampleDataStructure();
         storage.mount();
-        IDirectory root = storage.getRoot();
+        final IDirectory root = storage.getRoot();
         new Version(1, 1).saveTo(root);
         storage.unmount();
         dataStructure.open();
@@ -467,14 +407,14 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     {
         createExampleDataStructure();
         storage.mount();
-        IDirectory root = storage.getRoot();
+        final IDirectory root = storage.getRoot();
         new Version(2, 0).saveTo(root);
         storage.unmount();
         try
         {
             dataStructure.open();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals(
                     "Version of loaded data structure is V2.0 which is not backward compatible with V1.0",
@@ -487,8 +427,8 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     {
         createExampleDataStructure();
         storage.mount();
-        IDirectory root = storage.getRoot();
-        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
+        final IDirectory root = storage.getRoot();
+        final IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
         new Format(UnknownFormatV1_0.UNKNOWN_1_0.getCode(), new Version(1, 1), null)
                 .saveTo(metaData);
         storage.unmount();
@@ -501,8 +441,8 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     {
         createExampleDataStructure();
         storage.mount();
-        IDirectory root = storage.getRoot();
-        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
+        final IDirectory root = storage.getRoot();
+        final IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
         new Format(UnknownFormatV1_0.UNKNOWN_1_0.getCode(), new Version(2, 0), null)
                 .saveTo(metaData);
         storage.unmount();
@@ -511,7 +451,7 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
         {
             dataStructure.getFormattedData();
             fail("DataStructureException expected.");
-        } catch (DataStructureException e)
+        } catch (final DataStructureException e)
         {
             assertEquals("No class found for version V2.0", e.getMessage());
         }
@@ -522,8 +462,8 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     {
         createExampleDataStructure();
         storage.mount();
-        IDirectory root = storage.getRoot();
-        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
+        final IDirectory root = storage.getRoot();
+        final IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
         new Format("another format", new Version(1, 1), null).saveTo(metaData);
         storage.unmount();
         dataStructure.open();
@@ -538,21 +478,20 @@ public final class DataStructureTestV1_0 extends AbstractFileSystemTestCase
     public final static void createExampleDataStructure(final IStorage storage)
     {
         storage.mount();
-        IDirectory root = storage.getRoot();
+        final IDirectory root = storage.getRoot();
         new Version(1, 0).saveTo(root);
-        IDirectory data = root.makeDirectory(DataStructureV1_0.DIR_DATA);
-        IDirectory originalDataDir = data.makeDirectory(DataStructureV1_0.DIR_ORIGINAL);
+        final IDirectory data = root.makeDirectory(DataStructureV1_0.DIR_DATA);
+        final IDirectory originalDataDir = data.makeDirectory(DataStructureV1_0.DIR_ORIGINAL);
         originalDataDir.addKeyValuePair("file1", "This is my first file.");
-        IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA);
+        final IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA);
         new Format(UnknownFormatV1_0.UNKNOWN_1_0.getCode(), new Version(2, 0), null)
                 .saveTo(metaData);
         new ExperimentIdentifier("g", "p", "e").saveTo(metaData);
-        new ExperimentRegistratorDate(new Date(0)).saveTo(metaData);
+        new ExperimentRegistrationTimestamp(new Date(0)).saveTo(metaData);
         new ExperimentRegistrator("john", "doe", "j@doe").saveTo(metaData);
-        new MeasurementEntity("a", "b").saveTo(metaData);
+        new Sample("a", SampleType.CELL_PLATE, "b").saveTo(metaData);
         createExampleChecksum(metaData);
         metaData.addKeyValuePair(MappingFileHandler.MAPPING_FILE, "");
-        ProcessingType.COMPUTED_DATA.saveTo(metaData);
         storage.unmount();
     }
 
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/ExperimentIdentifierTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/ExperimentIdentifierTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4de2c95582b2faf973693c79d1d18dbf13aa5770
--- /dev/null
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/ExperimentIdentifierTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008 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.bds;
+
+import ch.systemsx.cisd.common.test.EqualsHashCodeTestCase;
+
+/**
+ * Test cases for corresponding {@link ExperimentIdentifier} class.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class ExperimentIdentifierTest extends EqualsHashCodeTestCase<ExperimentIdentifier>
+{
+
+    //
+    // EqualsHashCodeTestCase
+    //
+
+    @Override
+    protected final ExperimentIdentifier createInstance() throws Exception
+    {
+        return new ExperimentIdentifier("group", "project", "experiment1");
+    }
+
+    @Override
+    protected final ExperimentIdentifier createNotEqualInstance() throws Exception
+    {
+        return new ExperimentIdentifier("group", "project", "experiment2");
+    }
+}
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/SampleTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/SampleTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..db1d4751ae1e57fa02d14d9ce878e9bd2ac6bc4a
--- /dev/null
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/SampleTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 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.bds;
+
+import ch.systemsx.cisd.common.test.EqualsHashCodeTestCase;
+
+/**
+ * Test cases for corresponding {@link Sample} class.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class SampleTest extends EqualsHashCodeTestCase<Sample>
+{
+
+    //
+    // EqualsHashCodeTestCase
+    //
+
+    @Override
+    protected final Sample createInstance() throws Exception
+    {
+        return new Sample("sample", SampleType.CELL_PLATE, "description");
+    }
+
+    @Override
+    protected final Sample createNotEqualInstance() throws Exception
+    {
+        return new Sample("sample", SampleType.REINFECTION_PLATE, "description");
+    }
+
+}
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/UtilitiesTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/UtilitiesTest.java
index 8f9c0bfb7262e6bfee12d97d375f863c078eaeb8..e49e4d3a84a42380e73f531cf525bf69f964838b 100644
--- a/bds/sourceTest/java/ch/systemsx/cisd/bds/UtilitiesTest.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/UtilitiesTest.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.bds;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
@@ -106,4 +107,45 @@ public class UtilitiesTest extends AbstractFileSystemTestCase
         assertEquals("file1", nodes.get(2));
     }
 
+    @Test
+    public final void testGetBoolean()
+    {
+        try
+        {
+            Utilities.getBoolean(null, null);
+            fail("Directory and name can not be null.");
+        } catch (final AssertionError e)
+        {
+            // Nothing to do here.
+        }
+        final IDirectory directory = (IDirectory) NodeFactory.createNode(workingDirectory);
+        try
+        {
+            Utilities.getBoolean(directory, "doesNotExist");
+            fail("File 'doesNotExist' missing");
+        } catch (final DataStructureException e)
+        {
+            // Nothing to do here.
+        }
+        final String key = "bool";
+        final String value = "TRUE";
+        final IFile file = directory.addKeyValuePair(key, value);
+        final File[] listFiles = workingDirectory.listFiles();
+        assertEquals(1, listFiles.length);
+        assertEquals(key, listFiles[0].getName());
+        assertEquals(value, file.getStringContent().trim());
+        assertTrue(Utilities.getBoolean(directory, key));
+        directory.addKeyValuePair(key, "true");
+        try
+        {
+            Utilities.getBoolean(directory, key);
+            fail("Given value is not a boolean.");
+        } catch (final DataStructureException ex)
+        {
+            // Nothing to do here.
+        }
+        directory.addKeyValuePair(key, " FALSE ");
+        assertFalse(Utilities.getBoolean(directory, key));
+    }
+
 }
\ No newline at end of file