diff --git a/bds/source/java/ch/systemsx/cisd/bds/Constants.java b/bds/source/java/ch/systemsx/cisd/bds/Constants.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8f2415d6778578b2ddd907842eb933ff277ece3
--- /dev/null
+++ b/bds/source/java/ch/systemsx/cisd/bds/Constants.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * Some constants used inside the <i>BDS</i> library
+ *
+ * @author Christian Ribeaud
+ */
+public final class Constants
+{
+
+    /** The only accepted path separator (system independent). */
+    public final static char PATH_SEPARATOR = '/';
+
+    private Constants() {
+        // Can not be instantiated.
+    }
+}
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 0304ac73034a64017484f8892e1c5f688559a4cb..75fe887dd0ae20afebae8dc3978fb932be6d4e0b 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java
@@ -16,7 +16,7 @@
 
 package ch.systemsx.cisd.bds;
 
-import java.util.Map;
+import java.util.Set;
 
 import ch.systemsx.cisd.bds.handler.ChecksumHandler;
 import ch.systemsx.cisd.bds.handler.MappingFileHandler;
@@ -60,7 +60,8 @@ public class DataStructureV1_0 extends AbstractDataStructure
 
     private final void registerHandlers()
     {
-        mappingFileHandler = new MappingFileHandler(getMetaDataDirectory(), getStandardData(), getOriginalData());
+        mappingFileHandler =
+                new MappingFileHandler(getMetaDataDirectory(), getStandardData(), getOriginalData(), false);
         registerHandler(mappingFileHandler);
         registerHandler(new ChecksumHandler(getMetaDataDirectory().makeDirectory(ChecksumHandler.CHECKSUM_DIRECTORY),
                 getOriginalData()));
@@ -253,9 +254,9 @@ public class DataStructureV1_0 extends AbstractDataStructure
         mappingFileHandler.addReference(reference);
     }
 
-    public final Map<String, Reference> getStandardOriginalMapping()
+    public final Set<Reference> getStandardOriginalMapping()
     {
-        return mappingFileHandler.getStandardOriginalMapping();
+        return mappingFileHandler.getReferences();
     }
 
     //
diff --git a/bds/source/java/ch/systemsx/cisd/bds/Reference.java b/bds/source/java/ch/systemsx/cisd/bds/Reference.java
index 10e29533fbc7f234b70827976be8b1f62f72543c..854859b23c4dcf1861146ca0bd8b6e6313a73a03 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/Reference.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/Reference.java
@@ -23,9 +23,6 @@ package ch.systemsx.cisd.bds;
  */
 public final class Reference
 {
-    /** The only accepted path separator (system independent). */
-    public final static char PATH_SEPARATOR = '/';
-
     private final String path;
 
     private final String originalPath;
@@ -71,4 +68,35 @@ public final class Reference
     {
         return referenceType;
     }
+
+    //
+    // Object
+    //
+
+    @Override
+    public final boolean equals(final Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+        if (obj instanceof Reference == false)
+        {
+            return false;
+        }
+        final Reference that = (Reference) obj;
+        return that.path.equals(path);
+    }
+
+    @Override
+    public final int hashCode()
+    {
+        return path.hashCode();
+    }
+
+    @Override
+    public final String toString()
+    {
+        return getPath();
+    }
 }
diff --git a/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumBuilder.java b/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumBuilder.java
index 1c61153d728706990b04bf55ab49ab535eb3b439..aa6016e62c5252717c29718ecb649439445af23d 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumBuilder.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumBuilder.java
@@ -27,7 +27,7 @@ import java.util.List;
 
 import org.apache.commons.io.IOUtils;
 
-import ch.systemsx.cisd.bds.Reference;
+import ch.systemsx.cisd.bds.Constants;
 import ch.systemsx.cisd.bds.storage.IDirectory;
 import ch.systemsx.cisd.bds.storage.IFile;
 import ch.systemsx.cisd.bds.storage.INode;
@@ -81,7 +81,7 @@ class ChecksumBuilder
 
     private void addChecksum(PrintWriter printWriter, String path, INode node)
     {
-        String nodePath = (path == null ? "" : path + Reference.PATH_SEPARATOR) + node.getName();
+        String nodePath = (path == null ? "" : path + Constants.PATH_SEPARATOR) + node.getName();
         if (node instanceof IFile)
         {
             IFile file = (IFile) node;
diff --git a/bds/source/java/ch/systemsx/cisd/bds/handler/MappingFileHandler.java b/bds/source/java/ch/systemsx/cisd/bds/handler/MappingFileHandler.java
index d0222927db54a8d79b06542972f50da9b8bac071..e5a539316d6b1655524e10aa037f340119ef1f2a 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/handler/MappingFileHandler.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/handler/MappingFileHandler.java
@@ -16,13 +16,10 @@
 
 package ch.systemsx.cisd.bds.handler;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashMap;
+import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
+import java.util.Set;
 
 import ch.systemsx.cisd.bds.DataStructureException;
 import ch.systemsx.cisd.bds.IDataStructureHandler;
@@ -38,19 +35,20 @@ import ch.systemsx.cisd.bds.storage.IDirectory;
  */
 public final class MappingFileHandler implements IDataStructureHandler
 {
-    private final Map<String, Reference> standardOriginalMapping = new LinkedHashMap<String, Reference>();
+    private final Set<Reference> references = new HashSet<Reference>();
 
     /** The directory the mapping is going to be written to. */
     private final IDirectory mappingDirectory;
 
     /** The root of {@link Reference#getPath()}. Usually the path to <code>standard</code> directory. */
-    @SuppressWarnings("unused")
     private final IDirectory pathRoot;
 
     /** The root of {@link Reference#getOriginalPath()}. Usually the path to <code>original</code> directory. */
-    @SuppressWarnings("unused")
     private final IDirectory originalPathRoot;
 
+    /** Whether we should allow call to {@link #assertValid()}. */
+    private final boolean doValidation;
+
     /**
      * The mapping relating <i>standard</i> with <i>original</i> data.
      * <p>
@@ -61,7 +59,7 @@ public final class MappingFileHandler implements IDataStructureHandler
     public static final String MAPPING_FILE = "standard_original_mapping";
 
     public MappingFileHandler(final IDirectory mappingDirectory, final IDirectory pathRoot,
-            final IDirectory originalPathRoot)
+            final IDirectory originalPathRoot, final boolean doValidation)
     {
         assert mappingDirectory != null : "Given mapping directory can not be null.";
         assert pathRoot != null : "Given path root can not be null.";
@@ -69,6 +67,7 @@ public final class MappingFileHandler implements IDataStructureHandler
         this.mappingDirectory = mappingDirectory;
         this.pathRoot = pathRoot;
         this.originalPathRoot = originalPathRoot;
+        this.doValidation = doValidation;
     }
 
     /**
@@ -76,9 +75,9 @@ public final class MappingFileHandler implements IDataStructureHandler
      * 
      * @return an unmodifiable version of this map.
      */
-    public final Map<String, Reference> getStandardOriginalMapping()
+    public final Set<Reference> getReferences()
     {
-        return Collections.unmodifiableMap(standardOriginalMapping);
+        return Collections.unmodifiableSet(references);
     }
 
     /**
@@ -89,18 +88,17 @@ public final class MappingFileHandler implements IDataStructureHandler
     public final void addReference(final Reference reference) throws DataStructureException
     {
         assert reference != null : "Unspecified reference.";
-        final String path = reference.getPath();
-        if (standardOriginalMapping.containsKey(path))
+        if (references.contains(reference))
         {
-            throw new DataStructureException("There is already a reference for file '" + path + "'.");
+            throw new DataStructureException("There is already a reference for file '" + reference + "'.");
         }
-        standardOriginalMapping.put(path, reference);
+        references.add(reference);
     }
 
     private final void loadStandardOriginalMapping()
     {
         final List<String> mappingLines = Utilities.getStringList(mappingDirectory, MAPPING_FILE);
-        standardOriginalMapping.clear();
+        references.clear();
         for (int i = 0; i < mappingLines.size(); i++)
         {
             String referenceDefinition = mappingLines.get(i);
@@ -118,25 +116,23 @@ public final class MappingFileHandler implements IDataStructureHandler
                         + ": missing second tab character: " + referenceDefinition);
             }
             final ReferenceType type = ReferenceType.resolveByShortName(referenceDefinition.substring(i1 + 1, i2));
-            standardOriginalMapping.put(path, new Reference(path, referenceDefinition.substring(i2 + 1), type));
+            references.add(new Reference(path, referenceDefinition.substring(i2 + 1), type));
         }
     }
-    
-    // TODO 2007-11-30, Christian Ribeaud: list all nodes present in the standard directory. 
+
     private final String createMappingFile()
     {
-        final StringWriter writer = new StringWriter();
-        final PrintWriter printWriter = new PrintWriter(writer, true);
-        final Collection<Reference> values = standardOriginalMapping.values();
-        for (final Reference reference : values)
+        final StringBuilder builder = new StringBuilder();
+        for (final Reference reference : references)
         {
             final String path = reference.getPath();
             final String shortName = reference.getReferenceType().getShortName();
             final String originalPath = reference.getOriginalPath();
-            printWriter.println(path + "\t" + shortName + "\t" + originalPath);
+            builder.append(path).append("\t");
+            builder.append(shortName).append("\t");
+            builder.append(originalPath).append("\n");
         }
-        printWriter.close();
-        return writer.toString();
+        return builder.toString();
     }
 
     //
@@ -145,9 +141,24 @@ public final class MappingFileHandler implements IDataStructureHandler
 
     public final void assertValid() throws DataStructureException
     {
-        // TODO 2007-11-29, Christian Ribeaud: validation of loaded references. Note that this could interfere with
-        // checksum validation. To validate a checksum, the file must exist. So we would not need to check the original
-        // path existence here.
+        if (doValidation == false)
+        {
+            return;
+        }
+        final String errMsg = "Node '%s' not found in directory '%s'";
+        for (final Reference reference : references)
+        {
+            final String path = reference.getPath();
+            if (pathRoot.tryGetNode(path) == null)
+            {
+                throw new DataStructureException(String.format(errMsg, path, pathRoot));
+            }
+            final String originalPath = reference.getOriginalPath();
+            if (originalPathRoot.tryGetNode(originalPath) == null)
+            {
+                throw new DataStructureException(String.format(errMsg, originalPath, originalPathRoot));
+            }
+        }
     }
 
     public final void performClosing()
diff --git a/bds/source/java/ch/systemsx/cisd/bds/hcs/HCSImageFormattedData.java b/bds/source/java/ch/systemsx/cisd/bds/hcs/HCSImageFormattedData.java
index 400bd2fee1880a14af753590df6fd6f461a61702..c2ed9e925f357620f7a28cec9b09f71fe06aba26 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/hcs/HCSImageFormattedData.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/hcs/HCSImageFormattedData.java
@@ -146,6 +146,8 @@ public final class HCSImageFormattedData extends AbstractFormattedData implement
     public final INode tryGetStandardNodeAt(final int channel, final Location plateLocation, final Location wellLocation)
     {
         checkChannel(channel);
+        assert plateLocation != null : "Plate location can not be null.";
+        assert wellLocation != null : "Well location can not be null.";
         checkLocation(getPlateGeometry(), plateLocation);
         checkLocation(getWellGeometry(), wellLocation);
         final IDirectory standardDir = getStandardDataDirectory();
diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java
index f35e0adf9fa1a19a6d225301608fc9d052f847b4..8de90a92d2a130a9b413242a88fb67282e2bce8d 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java
@@ -30,12 +30,20 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
  */
 abstract class AbstractNode implements INode
 {
-    protected final static void moveFileToDirectory(final File source, final File directory)
+    protected final static File moveFileToDirectory(final File source, final File directory, final String nameOrNull)
             throws EnvironmentFailureException
     {
         assert source != null;
         assert directory != null && directory.isDirectory();
-        final File destination = new File(directory, source.getName());
+        final String newName;
+        if (nameOrNull == null)
+        {
+            newName = source.getName();
+        } else
+        {
+            newName = nameOrNull;
+        }
+        final File destination = new File(directory, newName);
         if (destination.exists() == false)
         {
             final boolean successful = source.renameTo(destination);
@@ -45,6 +53,7 @@ abstract class AbstractNode implements INode
                         .getAbsolutePath(), directory.getAbsolutePath());
             }
         }
+        return destination;
     }
 
     protected final File nodeFile;
@@ -84,7 +93,7 @@ abstract class AbstractNode implements INode
 
     public final void moveTo(final File directory)
     {
-        moveFileToDirectory(nodeFile, directory);
+        moveFileToDirectory(nodeFile, directory, null);
     }
 
     public boolean isValid()
diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java
index 6729aadf881250bbd3819eeff34b7d78a9ca4204..7738983457b06be8bc90443b8911bd804120d8e5 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java
@@ -21,6 +21,7 @@ import java.util.Iterator;
 
 import org.apache.commons.io.FileUtils;
 
+import ch.systemsx.cisd.bds.Constants;
 import ch.systemsx.cisd.bds.storage.IDirectory;
 import ch.systemsx.cisd.bds.storage.IFile;
 import ch.systemsx.cisd.bds.storage.ILink;
@@ -52,6 +53,29 @@ final class Directory extends AbstractNode implements IDirectory
         return ((AbstractNode) node).nodeFile;
     }
 
+    private final java.io.File findFile(final String name)
+    {
+        final java.io.File[] files = FileUtilities.listFiles(nodeFile);
+        for (final java.io.File file : files)
+        {
+            if (file.getName().equals(name))
+            {
+                return file;
+            }
+        }
+        return null;
+    }
+
+    private final static String cleanName(final String name)
+    {
+        final int index = name.indexOf(Constants.PATH_SEPARATOR);
+        if (index == 0)
+        {
+            return name.substring(1);
+        }
+        return name;
+    }
+
     //
     // IDirectory
     //
@@ -59,10 +83,19 @@ final class Directory extends AbstractNode implements IDirectory
     public final INode tryGetNode(final String name)
     {
         assert name != null : "Given name can not be null.";
-        final java.io.File[] files = FileUtilities.listFiles(nodeFile);
-        for (java.io.File file : files)
+        final String path = cleanName(name);
+        final int index = path.indexOf(Constants.PATH_SEPARATOR);
+        if (index > -1)
         {
-            if (file.getName().equals(name))
+            final java.io.File dir = findFile(path.substring(0, index));
+            if (dir != null)
+            {
+                return NodeFactory.createDirectoryNode(dir).tryGetNode(path.substring(index + 1));
+            }
+        } else
+        {
+            final java.io.File file = findFile(path);
+            if (file != null)
             {
                 return NodeFactory.createNode(file);
             }
@@ -106,7 +139,7 @@ final class Directory extends AbstractNode implements IDirectory
         final java.io.File newFile = new java.io.File(nodeFile, file.getName());
         if (move)
         {
-            moveFileToDirectory(file, nodeFile);
+            moveFileToDirectory(file, nodeFile, null);
         } else
         {
             try
@@ -135,7 +168,7 @@ final class Directory extends AbstractNode implements IDirectory
         final java.io.File fileLink = LinkMakerProvider.getDefaultLinkMaker().tryCreateLink(file, nodeFile, name);
         if (fileLink != null)
         {
-            final Link link = NodeFactory.createLinkNode(fileLink);
+            final Link link = (Link) NodeFactory.createLinkNode(name, file);
             link.setParent(this);
             return link;
         }
@@ -190,7 +223,7 @@ final class Directory extends AbstractNode implements IDirectory
         assert node != null : "Node can not be null";
         assert name != null : "Name can not be null.";
         final java.io.File file = getNodeFile(node);
-        return addFile(file, true);
+        return NodeFactory.createNode(moveFileToDirectory(file, nodeFile, name));
     }
 
     public final void removeNode(final INode node)
diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactory.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactory.java
index b647b9e5ad18ab72b1716f535681e5a91c0e0aba..cac88fa1ff0bda1e3ce3a7acb64a20c63ba84040 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactory.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactory.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 
 import ch.systemsx.cisd.bds.storage.IDirectory;
 import ch.systemsx.cisd.bds.storage.IFile;
+import ch.systemsx.cisd.bds.storage.ILink;
 import ch.systemsx.cisd.bds.storage.INode;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 
@@ -37,6 +38,10 @@ public final class NodeFactory
 
     /**
      * A <code>INode</code> factory method for given <var>file</var>.
+     * <p>
+     * IMPORTANT NOTE: we compare the absolute path against the canonical one to found out whether it is a link or not.
+     * This only works for <i>symbolic</i> links and not for <i>hard</i> links.
+     * </p>
      */
     public static INode createNode(final java.io.File file) throws EnvironmentFailureException
     {
@@ -67,11 +72,29 @@ public final class NodeFactory
         }
     }
 
-    public final static Link createLinkNode(final java.io.File file) throws EnvironmentFailureException
+    /**
+     * Creates a new <code>ILink</code> with given <var>name</var> which points to given <var>file</var>.
+     */
+    public final static ILink createLinkNode(final String name, final java.io.File file)
+    {
+        assert file != null : "Given file can not be null.";
+        assert name != null : "Given name can not be null.";
+        return new Link(name, createNode(file));
+    }
+
+    /**
+     * Creates a new <code>ILink</code>.
+     * <p>
+     * IMPORTANT NOTE: we compare the absolute path against the canonical one to found out whether it is a link or not.
+     * This only works for <i>symbolic</i> links and not for <i>hard</i> links.
+     * </p>
+     */
+    public final static ILink createLinkNode(final java.io.File file) throws EnvironmentFailureException
     {
-        final String absolutePath = file.getAbsolutePath();
         final String canonicalPath = getCanonicalPath(file);
-        assert absolutePath.equals(canonicalPath) == false : "Given file must be a link.";
+        final String absolutePath = file.getAbsolutePath();
+        assert absolutePath.equals(canonicalPath) == false : String.format(
+                "Given file must be a link [absolute=%s,canonical=%s].", absolutePath, canonicalPath);
         return new Link(file.getName(), createNode(new java.io.File(canonicalPath)));
     }
 
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java
index 389a4f8481708adaf0aff33b7ef38f3d4199d8ee..599a006cdd6771b60787c2d217ca47035f401b93 100644
--- a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java
@@ -25,7 +25,7 @@ import static org.testng.AssertJUnit.fail;
 import java.io.IOException;
 import java.util.Date;
 import java.util.Iterator;
-import java.util.Map;
+import java.util.Set;
 
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -203,9 +203,9 @@ public final class DataStructureV1_0Test extends AbstractFileSystemTestCase
     {
         dataStructure.create();
         dataStructure.addReference(new Reference("a", "b", ReferenceType.IDENTICAL));
-        Map<String, Reference> mapping = dataStructure.getStandardOriginalMapping();
+        final Set<Reference> mapping = dataStructure.getStandardOriginalMapping();
         assertEquals(1, mapping.size());
-        Reference actualReference = mapping.get("a");
+        final Reference actualReference = mapping.iterator().next();
         assertEquals("a", actualReference.getPath());
         assertEquals(ReferenceType.IDENTICAL, actualReference.getReferenceType());
         assertEquals("b", actualReference.getOriginalPath());
@@ -232,7 +232,7 @@ public final class DataStructureV1_0Test extends AbstractFileSystemTestCase
         dataStructure.create();
         try
         {
-            dataStructure.getStandardOriginalMapping().put("a", null);
+            dataStructure.getStandardOriginalMapping().add(null);
             fail("DataStructureException expected");
         } catch (UnsupportedOperationException e)
         {
@@ -401,16 +401,8 @@ public final class DataStructureV1_0Test extends AbstractFileSystemTestCase
         assertEquals(experimentRegistrator, reloadedDataStructure.getExperimentRegistrator());
         assertEquals(measurementEntity, reloadedDataStructure.getMeasurementEntity());
         assertEquals(ProcessingType.RAW_DATA, reloadedDataStructure.getProcessingType());
-        Map<String, Reference> mapping = reloadedDataStructure.getStandardOriginalMapping();
+        final Set<Reference> mapping = reloadedDataStructure.getStandardOriginalMapping();
         assertEquals(2, mapping.size());
-        Reference reference = mapping.get("a/b/c");
-        assertEquals("a/b/c", reference.getPath());
-        assertEquals(ReferenceType.IDENTICAL, reference.getReferenceType());
-        assertEquals("a6b8/x.t", reference.getOriginalPath());
-        reference = mapping.get("a78/jjh");
-        assertEquals("a78/jjh", reference.getPath());
-        assertEquals(ReferenceType.TRANSFORMED, reference.getReferenceType());
-        assertEquals("a b/x\tt", reference.getOriginalPath());
         checkFormattedData(reloadedDataStructure.getFormattedData());
 
         IDirectory metaDataDir = Utilities.getSubDirectory(root, DIR_METADATA);
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/handler/ChecksumHandlerTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/handler/ChecksumHandlerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..05512b28f8d868aa491fe925da6de615cbd3b7ec
--- /dev/null
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/handler/ChecksumHandlerTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.handler;
+
+import ch.systemsx.cisd.common.utilities.AbstractFileSystemTestCase;
+
+/**
+ * Test cases for corresponding {@link ChecksumHandler} class.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class ChecksumHandlerTest extends AbstractFileSystemTestCase
+{
+
+}
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/handler/MappingFileHandlerTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/handler/MappingFileHandlerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f23790a846c0557b04e6e1e9d8774ee81bdb8fc
--- /dev/null
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/handler/MappingFileHandlerTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.handler;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.bds.DataStructureException;
+import ch.systemsx.cisd.bds.Reference;
+import ch.systemsx.cisd.bds.ReferenceType;
+import ch.systemsx.cisd.bds.storage.IDirectory;
+import ch.systemsx.cisd.bds.storage.filesystem.NodeFactory;
+import ch.systemsx.cisd.common.utilities.AbstractFileSystemTestCase;
+
+/**
+ * Test cases for corresponding {@link MappingFileHandler} class.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class MappingFileHandlerTest extends AbstractFileSystemTestCase
+{
+
+    private final static String MAPPING_FILE_CONTENT =
+            "row1/row2_column1.tiff\tI\toriginal1.tiff\n" + "row2/row3_column2.tiff\tI\toriginal2.tiff\n";
+
+    private MappingFileHandler handler;
+
+    private final void prepareMappingFileHandler()
+    {
+        final IDirectory mappingDirectory = NodeFactory.createDirectoryNode(workingDirectory);
+        final IDirectory originalDirectory = mappingDirectory.makeDirectory("original");
+        final IDirectory standardDirectory = mappingDirectory.makeDirectory("standard");
+        handler = new MappingFileHandler(mappingDirectory, standardDirectory, originalDirectory, true);
+    }
+
+    private final void writeMappingFile() throws IOException
+    {
+        final File mappingFile = new File(workingDirectory, MappingFileHandler.MAPPING_FILE);
+        FileUtils.writeStringToFile(mappingFile, MAPPING_FILE_CONTENT);
+    }
+
+    private final void createMappedFiles() throws IOException
+    {
+        final File original = new File(workingDirectory, "original");
+        final File standard = new File(workingDirectory, "standard");
+        final File original1 = new File(original, "original1.tiff");
+        FileUtils.touch(original1);
+        assertTrue(original1.exists());
+        final File original2 = new File(original, "original2.tiff");
+        FileUtils.touch(original2);
+        assertTrue(original2.exists());
+        final File row1 = new File(standard, "row1");
+        row1.mkdir();
+        final File row2 = new File(standard, "row2");
+        row2.mkdir();
+        final File standard1 = new File(row1, "row2_column1.tiff");
+        FileUtils.touch(standard1);
+        assertTrue(standard1.exists());
+        final File standard2 = new File(row2, "row3_column2.tiff");
+        FileUtils.touch(standard2);
+        assertTrue(standard2.exists());
+    }
+
+    @Override
+    @BeforeMethod
+    public void setup() throws IOException
+    {
+        super.setup();
+        prepareMappingFileHandler();
+    }
+
+    @Test
+    public final void testAddReference()
+    {
+        try
+        {
+            handler.addReference(null);
+            fail("Null value not allowed.");
+        } catch (AssertionError ex)
+        {
+            // Nothing to do here.
+        }
+        handler.addReference(new Reference("1", "2", ReferenceType.IDENTICAL));
+        try
+        {
+            handler.addReference(new Reference("1", "2", ReferenceType.IDENTICAL));
+            fail("Can not added the same reference twice.");
+        } catch (DataStructureException ex)
+        {
+            // Nothing to do here.
+        }
+    }
+
+    @Test
+    public final void testPerformOpening() throws IOException
+    {
+        writeMappingFile();
+        handler.performOpening();
+        assertEquals(2, handler.getReferences().size());
+    }
+
+    @Test
+    public final void testPerformClosing() throws IOException
+    {
+        handler.addReference(new Reference("row1/row2_column1.tiff", "original1.tiff", ReferenceType.IDENTICAL));
+        handler.addReference(new Reference("row2/row3_column2.tiff", "original2.tiff", ReferenceType.IDENTICAL));
+        handler.performClosing();
+        final File mappingFile = new File(workingDirectory, MappingFileHandler.MAPPING_FILE);
+        assertTrue(mappingFile.exists());
+        final String mapping = FileUtils.readFileToString(mappingFile);
+        mapping.equals(MAPPING_FILE_CONTENT);
+    }
+
+    @Test
+    public final void testAssertValid() throws IOException
+    {
+        writeMappingFile();
+        handler.performOpening();
+        createMappedFiles();
+        handler.assertValid();
+    }
+
+}
\ No newline at end of file
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/hcs/HCSDataStructureV1_0Test.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/hcs/HCSDataStructureV1_0Test.java
index b3087dda8bc71e771be5cf7a0235f21b88a17157..f6a69e39e5061edeaf4a05cbde59d67b1144c72b 100644
--- a/bds/sourceTest/java/ch/systemsx/cisd/bds/hcs/HCSDataStructureV1_0Test.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/hcs/HCSDataStructureV1_0Test.java
@@ -21,12 +21,10 @@ import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
-import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.io.FileUtils;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -38,8 +36,6 @@ import ch.systemsx.cisd.bds.Format;
 import ch.systemsx.cisd.bds.FormatParameter;
 import ch.systemsx.cisd.bds.IDataStructure;
 import ch.systemsx.cisd.bds.IFormattedData;
-import ch.systemsx.cisd.bds.storage.IDirectory;
-import ch.systemsx.cisd.bds.storage.INode;
 import ch.systemsx.cisd.bds.storage.filesystem.FileStorage;
 import ch.systemsx.cisd.common.utilities.AbstractFileSystemTestCase;
 
@@ -109,51 +105,7 @@ public final class HCSDataStructureV1_0Test extends AbstractFileSystemTestCase
         assertEquals(format, formattedData.getFormat());
     }
 
-    @Test
-    public final void testGetNodeAt() throws IOException
-    {
-        dataStructure.create();
-        DataStructureV1_0Test.createExampleDataStructure(storage);
-        setFormatAndFormatParameters();
-        final IDirectory standardData = dataStructure.getStandardData();
-        final IDirectory channelDir = standardData.makeDirectory(Channel.CHANNEL + "1");
-        final IDirectory plateRowDir = channelDir.makeDirectory(HCSImageFormattedData.ROW + "1");
-        final IDirectory plateColumnDir = plateRowDir.makeDirectory(HCSImageFormattedData.COLUMN + "1");
-        final String wellFileName = HCSImageFormattedData.createWellFileName(new Location(1, 1));
-        final File wellFile = new File(workingDirectory, wellFileName);
-        FileUtils.writeStringToFile(wellFile, "This is an image...");
-        plateColumnDir.addFile(wellFile, true);
-        final IHCSFormattedData formattedData = (IHCSFormattedData) dataStructure.getFormattedData();
-        try
-        {
-            formattedData.tryGetStandardNodeAt(3, new Location(1, 1), new Location(1, 1));
-            fail("3 > 2");
-        } catch (IndexOutOfBoundsException ex)
-        {
-            // Nothing to do here.
-        }
-        try
-        {
-            formattedData.tryGetStandardNodeAt(2, new Location(1, 1), new Location(1, 1));
-            fail("No directory named 'channel2' found.");
-        } catch (DataStructureException ex)
-        {
-            assertTrue(ex.getMessage().indexOf("'channel2'") > -1);
-        }
-        try
-        {
-            formattedData.tryGetStandardNodeAt(1, new Location(1, 3), new Location(1, 1));
-            fail("Given geometry '2x3' does not contain location '[x=1,y=3]'.");
-        } catch (IllegalArgumentException ex)
-        {
-            assertTrue(ex.getMessage().indexOf("does not contain location") > -1);
-        }
-        final INode node = formattedData.tryGetStandardNodeAt(1, new Location(1, 1), new Location(1, 1));
-        assertEquals("row1_column1.tiff", node.getName());
-        dataStructure.close();
-    }
-
-    @Test
+    @Test(dependsOnMethods="testGetFormatedData")
     public final void testHCSImageDataStructure()
     {
         // Creating...
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/hcs/HCSImageFormattedDataTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/hcs/HCSImageFormattedDataTest.java
index 24849e23e56d6d29b90098e36bb79a064288d6a5..7a4ff83429f9be9524fd07b6607b57eab5ad732b 100644
--- a/bds/sourceTest/java/ch/systemsx/cisd/bds/hcs/HCSImageFormattedDataTest.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/hcs/HCSImageFormattedDataTest.java
@@ -18,6 +18,8 @@ package ch.systemsx.cisd.bds.hcs;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
 import java.io.File;
@@ -36,6 +38,8 @@ import ch.systemsx.cisd.bds.DataStructureV1_0;
 import ch.systemsx.cisd.bds.FormatedDataFactory;
 import ch.systemsx.cisd.bds.IFormatParameters;
 import ch.systemsx.cisd.bds.storage.IDirectory;
+import ch.systemsx.cisd.bds.storage.IFile;
+import ch.systemsx.cisd.bds.storage.ILink;
 import ch.systemsx.cisd.bds.storage.INode;
 import ch.systemsx.cisd.bds.storage.filesystem.NodeFactory;
 import ch.systemsx.cisd.common.utilities.AbstractFileSystemTestCase;
@@ -86,9 +90,9 @@ public class HCSImageFormattedDataTest extends AbstractFileSystemTestCase
     private final void prepareStandardNode()
     {
         standardNode = NodeFactory.createDirectoryNode(workingDirectory);
-        final IDirectory channel1 = standardNode.makeDirectory("channel1");
-        final IDirectory row1 = channel1.makeDirectory("row1");
-        leafDirectory = row1.makeDirectory("column2");
+        final IDirectory channel1 = standardNode.makeDirectory(Channel.CHANNEL + "1");
+        final IDirectory row1 = channel1.makeDirectory(HCSImageFormattedData.ROW + "1");
+        leafDirectory = row1.makeDirectory(HCSImageFormattedData.COLUMN + "2");
     }
 
     private final void addParameterCheckExpectations(final Expectations exp)
@@ -163,9 +167,9 @@ public class HCSImageFormattedDataTest extends AbstractFileSystemTestCase
     public final void testAddStandardNodeWithOriginalData() throws IOException
     {
         final String originalFileName = "original.txt";
-        FileUtils.touch(new File(workingDirectory, originalFileName));
+        FileUtils.writeStringToFile(new File(workingDirectory, originalFileName), "This is my original file...");
         final int channelIndex = 1;
-        final IDirectory workingDirectoryNode = NodeFactory.createDirectoryNode(workingDirectory);
+        final IDirectory originalNode = NodeFactory.createDirectoryNode(workingDirectory);
         context.checking(new Expectations()
             {
                 {
@@ -175,25 +179,166 @@ public class HCSImageFormattedDataTest extends AbstractFileSystemTestCase
                     will(returnValue(standardNode));
 
                     one(directory).tryGetNode(DataStructureV1_0.DIR_ORIGINAL);
-                    will(returnValue(workingDirectoryNode));
+                    will(returnValue(originalNode));
 
                     one(formatParameters).getValue(HCSImageFormat1_0.CONTAINS_ORIGINAL_DATA);
                     will(returnValue(Boolean.FALSE));
                 }
             });
         final INode node = formattedData.addStandardNode(originalFileName, channelIndex, PLATE_LOCATION, WELL_LOCATION);
+        final String standardFileName = "row2_column1.tiff";
         assertNotNull(node);
-        assertEquals(originalFileName, node.getName());
-        final INode standardFile = leafDirectory.tryGetNode(originalFileName);
+        assertEquals(standardFileName, node.getName());
+        // Look at the standard leaf directory if the node is there as well.
+        final INode standardFile = leafDirectory.tryGetNode(standardFileName);
         assertNotNull(standardFile);
-        assertEquals(originalFileName, standardFile.getName());
+        assertTrue(standardFile instanceof IFile);
+        assertEquals(standardFileName, standardFile.getName());
+        // Node should no longer be in original directory
+        assertNull(originalNode.tryGetNode(originalFileName));
         context.assertIsSatisfied();
     }
 
     @Test
-    public final void testTryGetStandardNodeAt()
+    public final void testAddStandardNodeWithoutOriginalData() throws IOException
     {
+        final String originalFileName = "original.tiff";
+        FileUtils.writeStringToFile(new File(workingDirectory, originalFileName), "This is my original file...");
+        final int channelIndex = 1;
+        final IDirectory originalNode = NodeFactory.createDirectoryNode(workingDirectory);
+        context.checking(new Expectations()
+            {
+                {
+                    addParameterCheckExpectations(this);
+
+                    exactly(2).of(directory).tryGetNode(DataStructureV1_0.DIR_STANDARD);
+                    will(returnValue(standardNode));
+
+                    one(directory).tryGetNode(DataStructureV1_0.DIR_ORIGINAL);
+                    will(returnValue(originalNode));
+
+                    one(formatParameters).getValue(HCSImageFormat1_0.CONTAINS_ORIGINAL_DATA);
+                    will(returnValue(Boolean.TRUE));
+                }
+            });
+        final INode node = formattedData.addStandardNode(originalFileName, channelIndex, PLATE_LOCATION, WELL_LOCATION);
+        final String standardFileName = "row2_column1.tiff";
+        assertNotNull(node);
+        assertTrue(node instanceof ILink);
+        assertEquals(standardFileName, node.getName());
+        // Look at the standard leaf directory if the node is there as well.
+        final INode standardFile = leafDirectory.tryGetNode(standardFileName);
+        assertNotNull(standardFile);
+        assertTrue(standardFile instanceof IFile);
+        assertEquals(standardFileName, standardFile.getName());
+        // Node should still be in original directory
+        assertNotNull(originalNode.tryGetNode(originalFileName));
+        context.assertIsSatisfied();
 
+    }
+
+    @Test
+    public final void testTryGetStandardNodeAtWithNoFile()
+    {
+        final int channelIndex = 1;
+        context.checking(new Expectations()
+            {
+                {
+                    addParameterCheckExpectations(this);
+
+                    one(directory).tryGetNode(DataStructureV1_0.DIR_STANDARD);
+                    will(returnValue(standardNode));
+                }
+            });
+        final INode node = formattedData.tryGetStandardNodeAt(channelIndex, PLATE_LOCATION, WELL_LOCATION);
+        assertNull(node);
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public final void testTryGetStandardNodeAtWithFile() throws IOException
+    {
+        final File file = new File(workingDirectory, "row2_column1.tiff");
+        FileUtils.writeStringToFile(file, "This is my original file...");
+        leafDirectory.addFile(file, true);
+        final int channelIndex = 1;
+        context.checking(new Expectations()
+            {
+                {
+                    addParameterCheckExpectations(this);
+
+                    one(directory).tryGetNode(DataStructureV1_0.DIR_STANDARD);
+                    will(returnValue(standardNode));
+                }
+            });
+        final INode node = formattedData.tryGetStandardNodeAt(channelIndex, PLATE_LOCATION, WELL_LOCATION);
+        assertNotNull(node);
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public final void testTryGetStandardNodeAtWithWrongChannelIndex()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(formatParameters).getValue(ChannelList.NUMBER_OF_CHANNELS);
+                    will(returnValue(createChannelList()));
+                }
+            });
+        try
+        {
+            formattedData.tryGetStandardNodeAt(2, null, null);
+            fail("2 > 1");
+        } catch (IndexOutOfBoundsException ex)
+        {
+            // Nothing to do here.
+        }
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public final void testTryGetStandardNodeAtWithWrongPlateLocation()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(formatParameters).getValue(ChannelList.NUMBER_OF_CHANNELS);
+                    will(returnValue(createChannelList()));
+
+                    one(formatParameters).getValue(PlateGeometry.PLATE_GEOMETRY);
+                    will(returnValue(new Geometry(2, 2)));
+                }
+            });
+        try
+        {
+            final Location location = new Location(2, 3);
+            formattedData.tryGetStandardNodeAt(1, location, location);
+            fail("Given geometry '2x2' does not contain location '[x=2,y=3]'");
+        } catch (IllegalArgumentException ex)
+        {
+            // Nothing to do here.
+        }
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public final void testTryGetStandardNodeAtWithWrongWellLocation()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    addParameterCheckExpectations(this);
+                }
+            });
+        try
+        {
+            formattedData.tryGetStandardNodeAt(1, new Location(2, 2), new Location(3, 2));
+            fail("Given geometry '2x2' does not contain location '[x=3,y=2]'");
+        } catch (IllegalArgumentException ex)
+        {
+            // Nothing to do here.
+        }
         context.assertIsSatisfied();
     }
 }
\ No newline at end of file