diff --git a/bds/.classpath b/bds/.classpath
index 66650071986d07f82973dd5a46d84f837c1a4fd7..c9772c5f8e35106dcf90c4daeec72c84270a137d 100644
--- a/bds/.classpath
+++ b/bds/.classpath
@@ -1,9 +1,10 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="source/java"/>
-	<classpathentry kind="src" path="sourceTest/java"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/common"/>
-	<classpathentry kind="lib" path="/libraries/commons-io/commons-io.jar" sourcepath="/libraries/commons-io/src.zip"/>
-	<classpathentry kind="output" path="targets/classes"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="source/java"/>
+	<classpathentry kind="src" path="sourceTest/java"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/common"/>
+	<classpathentry kind="lib" path="/libraries/commons-io/commons-io.jar" sourcepath="/libraries/commons-io/src.zip"/>
+	<classpathentry kind="lib" path="/libraries/testng/testng-jdk15.jar" sourcepath="/libraries/testng/src.zip"/>
+	<classpathentry kind="output" path="targets/classes"/>
+</classpath>
diff --git a/bds/resource/dependency-structure.ddf b/bds/resource/dependency-structure.ddf
index 1a06b3ffd5a964807fa1f8d7d96d7a481e564957..5697bea2773dd1015cd0f5cc752de168b415c7c9 100644
--- a/bds/resource/dependency-structure.ddf
+++ b/bds/resource/dependency-structure.ddf
@@ -1,7 +1,23 @@
 #
 #
 #
-
-#show allResults
+show allResults
 
 {package} = ch.systemsx.cisd.bds
+
+[storage] = ${package}.storage.* excluding ${package}.storage.*.*
+check sets [storage]
+
+[storage.filesystem] = ${package}.storage.filesystem.*
+[storage.hdf5] = ${package}.storage.hdf5.*
+check sets [storage.filesystem] [storage.hdf5]
+
+[main] = ${package}.* excluding ${package}.*.*
+check sets [main]
+
+layer layer0 = [storage]
+layer layer1 = [storage.filesystem] [storage.hdf5]
+layer layer2 = [main]
+
+check layeringOf layer0 layer1 layer2
+
diff --git a/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java b/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java
index d59a850ca6d52c3254ef8df060d5dd76ae4b9b01..8ab5d894f934263be333324dceb641162acbb462 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java
@@ -34,9 +34,9 @@ public class ExperimentIdentifier
     public static ExperimentIdentifier loadFrom(IDirectory directory)
     {
         IDirectory idFolder = Utilities.getSubDirectory(directory, FOLDER);
-        String groupCode = Utilities.getString(idFolder, GROUP_CODE);
-        String projectCode = Utilities.getString(idFolder, PROJECT_CODE);
-        String experimentCode = Utilities.getString(idFolder, EXPERIMENT_CODE);
+        String groupCode = Utilities.getTrimmedString(idFolder, GROUP_CODE);
+        String projectCode = Utilities.getTrimmedString(idFolder, PROJECT_CODE);
+        String experimentCode = Utilities.getTrimmedString(idFolder, EXPERIMENT_CODE);
         return new ExperimentIdentifier(groupCode, projectCode, experimentCode);
     }
     
diff --git a/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java b/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java
index e4aaaa5875beac7b0a796a0c78c710a5adb224ce..791c3822025bfe7910a458ca53149821089ecef3 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java
@@ -43,7 +43,7 @@ public enum ProcessingType
     
     public static ProcessingType loadFrom(IDirectory directory)
     {
-        return resolve(Utilities.getString(directory, PROCESSING_TYPE));
+        return resolve(Utilities.getTrimmedString(directory, PROCESSING_TYPE));
     }
     
     public void saveTo(IDirectory directory)
diff --git a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java
index fff492ed4639b13adfc92226e8e0f7586eceaa27..fe35444a1590d92a340d8ed042eb4893111d8ffa 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java
@@ -38,6 +38,11 @@ public class Utilities
         return (IDirectory) node;
     }
     
+    public static String getTrimmedString(IDirectory directory, String name)
+    {
+        return getString(directory, name).trim();
+    }
+
     public static String getString(IDirectory directory, String name)
     {
         INode node = directory.getNode(name);
@@ -45,12 +50,12 @@ public class Utilities
         {
             throw new UserFailureException("File '" + name + "' missing in " + directory);
         }
-        if (node instanceof IFile<?> == false)
+        if (node instanceof IFile == false)
         {
             throw new UserFailureException(node + " is not a file.");
         }
-        IFile<?> file = (IFile<?>) node;
-        return file.getValue().toString();
+        IFile file = (IFile) node;
+        return file.getStringContent();
     }
     
 }
diff --git a/bds/source/java/ch/systemsx/cisd/bds/Version.java b/bds/source/java/ch/systemsx/cisd/bds/Version.java
index 561d8090d5fa013a23e8607e8e429dfb3176b7d4..3a3eb319295865ae6fa94134d6e53fd0ae1b852a 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/Version.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/Version.java
@@ -38,7 +38,7 @@ public final class Version
     
     private static int getNumber(IDirectory versionFolder, String name)
     {
-        String value = Utilities.getString(versionFolder, name);
+        String value = Utilities.getTrimmedString(versionFolder, name);
         try
         {
             return Integer.parseInt(value);
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 b66fb1f301b98bbbfecfa22428d3070c740693ba..607d7375f6e795db0926518ae1686daa38f2ec25 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java
@@ -29,9 +29,9 @@ public interface IDirectory extends INode, Iterable<INode>
     
     public IDirectory makeDirectory(String name);
     
-    public IFile<File> addRealFile(File file);
+    public INode addFile(File file);
     
-    public IFile<String> addKeyValuePair(String key, String value);
+    public IFile addKeyValuePair(String key, String value);
     
     public ILink addLink(String name, INode node);
 }
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 c657dcbb2d422445390c6c2fabe94ac48a96c9d3..6a3b733bbb2cd21eae961f5b6ab77ab03f66add7 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java
@@ -21,10 +21,15 @@ package ch.systemsx.cisd.bds.storage;
  *
  * @author Franz-Josef Elmer
  */
-public interface IFile<T> extends INode
+public interface IFile extends INode
 {
     /**
-     * Returns the value (or content) of this file node.
+     * Returns the content of this file node as a byte array.
      */
-    public T getValue();
+    public byte[] getBinaryContent();
+    
+    /**
+     * Returns the content of this file node as a string.
+     */
+    public String getStringContent();
 }
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 18af3dec735c419bd83772bb1d567ec99498f1e3..a07ca45f6a43072ebe2569bde78d38f9b170e0ff 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
@@ -33,6 +33,7 @@ abstract class AbstractNode implements INode
     AbstractNode(File file)
     {
         assert file != null : "Unspecified file";
+        assert file.exists() : "Non existing file " + file;
         this.nodeFile = file;
     }
     
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 f0ae2972dbb9accc3c022446bee142bdefe0cfb8..0ddf8d91dba7cb6c9421eae8d0bf61821bc8ca39 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
@@ -16,7 +16,6 @@
 
 package ch.systemsx.cisd.bds.storage.filesystem;
 
-import java.io.File;
 import java.util.Iterator;
 
 import ch.systemsx.cisd.bds.storage.IDirectory;
@@ -28,13 +27,11 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.utilities.FileUtilities;
 
 /**
- * 
- *
  * @author Franz-Josef Elmer
  */
 class Directory extends AbstractNode implements IDirectory
 {
-    Directory(File directory)
+    Directory(java.io.File directory)
     {
         super(directory);
         assert directory.isDirectory() : "Not a directory: " + directory.getAbsolutePath();
@@ -42,8 +39,8 @@ class Directory extends AbstractNode implements IDirectory
     
     public INode getNode(String name)
     {
-        File[] files = nodeFile.listFiles();
-        for (File file : files)
+        java.io.File[] files = nodeFile.listFiles();
+        for (java.io.File file : files)
         {
             if (file.getName().equals(name))
             {
@@ -55,10 +52,10 @@ class Directory extends AbstractNode implements IDirectory
 
     public IDirectory makeDirectory(String name)
     {
-        File dir = new File(nodeFile, name);
+        java.io.File dir = new java.io.File(nodeFile, name);
         if (dir.exists())
         {
-            throw new UserFailureException("There already exists a file named '" + name + "' directory " + this);
+            throw new UserFailureException("There already exists a file named '" + name + "' in directory " + this);
         }
         boolean successful = dir.mkdir();
         if (successful == false)
@@ -69,18 +66,18 @@ class Directory extends AbstractNode implements IDirectory
         return new Directory(dir);
     }
 
-    public IFile<String> addKeyValuePair(String key, String value)
+    public IFile addKeyValuePair(String key, String value)
     {
-        File file = new File(nodeFile, key);
+        java.io.File file = new java.io.File(nodeFile, key);
         FileUtilities.writeToFile(file, value);
-        return new StringFile(file);
+        return new File(file);
     }
 
-    public IFile<File> addRealFile(File file)
+    public INode addFile(java.io.File file)
     {
-        File newFile = new File(nodeFile, file.getName());
-        FileUtilities.copyFileTo(file, newFile, true);
-        return new FileFile(newFile);
+        INode node = NodeFactory.createNode(file);
+        node.extractTo(nodeFile);
+        return node;
     }
 
     public ILink addLink(String name, INode node)
@@ -93,7 +90,7 @@ class Directory extends AbstractNode implements IDirectory
     {
         return new Iterator<INode>()
             {
-                private File[] files = nodeFile.listFiles();
+                private java.io.File[] files = nodeFile.listFiles();
                 private int index;
                 
                 public void remove()
@@ -113,9 +110,9 @@ class Directory extends AbstractNode implements IDirectory
             };
     }
 
-    public void extractTo(File directory) throws UserFailureException, EnvironmentFailureException
+    public void extractTo(java.io.File directory) throws UserFailureException, EnvironmentFailureException
     {
-        File destination = new File(directory, getName());
+        java.io.File destination = new java.io.File(directory, getName());
         if (destination.mkdirs() == false)
         {
             throw new EnvironmentFailureException("Couldn't create directory for some unknown reason: "
diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractFileNode.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java
similarity index 62%
rename from bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractFileNode.java
rename to bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java
index 5ba84d3adc765713a0db6a6650d75d69938f21e0..1b3487f3003c745bb88fc3fce39470c31e289c6c 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractFileNode.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java
@@ -16,7 +16,6 @@
 
 package ch.systemsx.cisd.bds.storage.filesystem;
 
-import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -26,33 +25,56 @@ import org.apache.commons.io.IOUtils;
 import ch.systemsx.cisd.bds.storage.IFile;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.utilities.FileUtilities;
 
 /**
  * 
  *
  * @author Franz-Josef Elmer
  */
-abstract class AbstractFileNode<T> extends AbstractNode implements IFile<T>
+class File extends AbstractNode implements IFile
 {
-    AbstractFileNode(File file)
+    File(java.io.File file)
     {
         super(file);
         assert file.isFile() : "Not a file " + file.getAbsolutePath();
     }
+    
+    public byte[] getBinaryContent()
+    {
+        FileInputStream inputStream = null;
+        try
+        {
+            inputStream = new FileInputStream(nodeFile);
+            return IOUtils.toByteArray(inputStream);
+        } catch (IOException ex)
+        {
+            throw new EnvironmentFailureException("Couldn't get data from file " + nodeFile.getAbsolutePath(), ex);
+        } finally
+        {
+            IOUtils.closeQuietly(inputStream);
+        }
+    }
+
+    public String getStringContent()
+    {
+        return FileUtilities.loadToString(nodeFile);
+    }
 
-    public void extractTo(File directory) throws UserFailureException, EnvironmentFailureException
+    public void extractTo(java.io.File directory) throws UserFailureException, EnvironmentFailureException
     {
         FileInputStream inputStream = null;
         FileOutputStream outputStream = null;
         try
         {
             inputStream = new FileInputStream(nodeFile);
-            outputStream = new FileOutputStream(new File(directory, getName()));
+            directory.mkdirs();
+            outputStream = new FileOutputStream(new java.io.File(directory, getName()));
             IOUtils.copy(inputStream, outputStream);
         } catch (IOException ex)
         {
             throw new EnvironmentFailureException("Couldn't extract file '" + this + "' to directory "
-                    + directory.getAbsolutePath());
+                    + directory.getAbsolutePath(), ex);
         } finally
         {
             IOUtils.closeQuietly(inputStream);
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 23db215d3864edf84115c1a8a9f56ca98d0e6677..82169ce3f18ee21545778ba8e7eb004f0d4ed65c 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
@@ -16,7 +16,6 @@
 
 package ch.systemsx.cisd.bds.storage.filesystem;
 
-import java.io.File;
 import java.io.IOException;
 
 import ch.systemsx.cisd.bds.storage.INode;
@@ -29,7 +28,7 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
  */
 class NodeFactory
 {
-    static INode createNode(File file)
+    static INode createNode(java.io.File file)
     {
         assert file != null : "Unspecified node";
         String absolutePath = file.getAbsolutePath();
@@ -38,13 +37,13 @@ class NodeFactory
             String canonicalPath = file.getCanonicalPath();
             if (absolutePath.equals(canonicalPath) == false)
             {
-                return new Link(file.getName(), createNode(new File(canonicalPath)));
+                return new Link(file.getName(), createNode(new java.io.File(canonicalPath)));
             }
             if (file.isDirectory())
             {
                 return new Directory(file);
             }
-            return new StringFile(file);
+            return new File(file);
         } catch (IOException ex)
         {
             throw new EnvironmentFailureException("Couldn't get canonical path of file " + absolutePath);
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/.gitignore b/bds/sourceTest/java/ch/systemsx/cisd/bds/.gitignore
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cc91efe4ffbfe8380a73393cfe60f9bcbb42584
--- /dev/null
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.storage.filesystem;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.io.File;
+
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.bds.storage.IDirectory;
+import ch.systemsx.cisd.bds.storage.IFile;
+import ch.systemsx.cisd.bds.storage.INode;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.utilities.FileUtilities;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class DirectoryTest extends StorageTestCase
+{
+    @Test
+    public void testGetName()
+    {
+        Directory directory = new Directory(TEST_DIR);
+        assertEquals(TEST_DIR.getName(), directory.getName());
+    }
+    
+    @Test
+    public void testMakeDirectory()
+    {
+        Directory directory = new Directory(TEST_DIR);
+        IDirectory subdirectory = directory.makeDirectory("sub-directory");
+        
+        assertEquals("sub-directory", subdirectory.getName());
+        File subdir = new File(TEST_DIR, "sub-directory");
+        assertEquals(true, subdir.exists());
+        assertEquals(true, subdir.isDirectory());
+    }
+    
+    @Test
+    public void testMakeDirectoryTwice()
+    {
+        Directory directory = new Directory(TEST_DIR);
+        directory.makeDirectory("sub-directory");
+        try
+        {
+            directory.makeDirectory("sub-directory");
+            AssertJUnit.fail("UserFailureException because a directory can made only once.");
+        } catch (UserFailureException e)
+        {
+            assertTrue(e.getMessage().indexOf("sub-directory") >= 0);
+        }
+    }
+    
+    @Test
+    public void testAddKeyValuePair()
+    {
+        IFile stringFile = new Directory(TEST_DIR).addKeyValuePair("answer", "42");
+        assertEquals("42\n", FileUtilities.loadToString(new File(TEST_DIR, "answer")));
+        assertEquals("42\n", stringFile.getStringContent());
+    }
+    
+    @Test
+    public void testExtractTo()
+    {
+        File dir = new File(TEST_DIR, "dir");
+        dir.mkdirs();
+        Directory directory = new Directory(dir);
+        directory.addKeyValuePair("p1", "property 1");
+        IDirectory subdir = directory.makeDirectory("subdir");
+        subdir.addKeyValuePair("p2", "property 2");
+        File destination = new File(TEST_DIR, "destination");
+        assertFalse(destination.exists());
+        
+        directory.extractTo(destination);
+        
+        assertTrue(destination.exists());
+        File copiedDir = new File(destination, "dir");
+        assertTrue(copiedDir.exists());
+        assertEquals("property 1\n", FileUtilities.loadToString(new File(copiedDir, "p1")));
+        File copiedSubDir = new File(copiedDir, "subdir");
+        assertTrue(copiedSubDir.isDirectory());
+        assertEquals("property 2\n", FileUtilities.loadToString(new File(copiedSubDir, "p2")));
+    }
+    
+    @Test
+    public void testAddFile()
+    {
+        File dir = new File(TEST_DIR, "dir");
+        dir.mkdirs();
+        FileUtilities.writeToFile(new File(dir, "p1"), "property 1");
+        File subDir = new File(dir, "subdir");
+        subDir.mkdir();
+        FileUtilities.writeToFile(new File(subDir, "p2"), "property 2");
+        File dest = new File(TEST_DIR, "destination");
+        dest.mkdir();
+        Directory directory = new Directory(dest);
+        
+        INode copiedDir = directory.addFile(dir);
+        
+        assertEquals("dir", copiedDir.getName());
+        assertTrue(copiedDir instanceof IDirectory);
+        File copiedRealDir = new File(dest, "dir");
+        assertTrue(copiedRealDir.isDirectory());
+        IDirectory cd = (IDirectory) copiedDir;
+        INode node = cd.getNode("p1");
+        assertNotNull(node);
+        assertTrue(node instanceof IFile);
+        assertEquals("property 1\n", ((IFile) node).getStringContent());
+        assertEquals("property 1\n", FileUtilities.loadToString(new File(copiedRealDir, "p1")));
+        node = cd.getNode("subdir");
+        assertEquals("subdir", node.getName());
+        assertNotNull(node);
+        assertTrue(node instanceof IDirectory);
+        node = ((IDirectory) node).getNode("p2");
+        File copiedRealSubDir = new File(copiedRealDir, "subdir");
+        assertTrue(copiedRealSubDir.isDirectory());
+        assertEquals("p2", node.getName());
+        assertTrue(node instanceof IFile);
+        assertEquals("property 2\n", ((IFile) node).getStringContent());
+        assertEquals("property 2\n", FileUtilities.loadToString(new File(copiedRealSubDir, "p2")));
+    }
+}
diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/FileFile.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileStorageTest.java
similarity index 69%
rename from bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/FileFile.java
rename to bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileStorageTest.java
index 9131b26f9f61804468dff4c9c5dd1f405f3d6ed7..386431cf05b99cdceb8e5d49fb89a1daa882f110 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/FileFile.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileStorageTest.java
@@ -16,23 +16,20 @@
 
 package ch.systemsx.cisd.bds.storage.filesystem;
 
-import java.io.File;
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
 
 /**
  * 
  *
  * @author Franz-Josef Elmer
  */
-class FileFile extends AbstractFileNode<File>
+public class FileStorageTest extends StorageTestCase
 {
-    public FileFile(File file)
+    @Test
+    public void testGetRoot()
     {
-        super(file);
+        FileStorage fileStorage = new FileStorage(TEST_DIR);
+        AssertJUnit.assertEquals(TEST_DIR.getName(), fileStorage.getRoot().getName());
     }
-
-    public File getValue()
-    {
-        return nodeFile;
-    }
-
 }
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..29346c1a6180a935c02cb1bc497d70505f795096
--- /dev/null
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.storage.filesystem;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.common.utilities.FileUtilities;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class FileTest extends StorageTestCase
+{
+    @Test
+    public void testGetValueAndGetName()
+    {
+        java.io.File file = new java.io.File(TEST_DIR, "test.txt");
+        FileUtilities.writeToFile(file, "Hello\nworld!\n");
+        File stringFile = new File(file);
+        
+        assertEquals("test.txt", stringFile.getName());
+        assertEquals("Hello\nworld!\n", stringFile.getStringContent());
+        assertEquals("Hello\nworld!\n", new String(stringFile.getBinaryContent()));
+    }
+    
+    @Test
+    public void testExtractTo()
+    {
+        java.io.File file = new java.io.File(TEST_DIR, "test.txt");
+        FileUtilities.writeToFile(file, "Hello\nworld!\n");
+        File stringFile = new File(file);
+
+        java.io.File subdir = new java.io.File(TEST_DIR, "subdir");
+        stringFile.extractTo(subdir);
+        assertEquals("Hello\nworld!\n", FileUtilities.loadToString(new java.io.File(subdir, stringFile.getName())));
+    }
+}
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactoryTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff9b70135edcb24ceff502d81daf2e519127d388
--- /dev/null
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactoryTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.storage.filesystem;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.bds.storage.IDirectory;
+import ch.systemsx.cisd.bds.storage.IFile;
+import ch.systemsx.cisd.bds.storage.INode;
+import ch.systemsx.cisd.common.utilities.FileUtilities;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class NodeFactoryTest extends StorageTestCase
+{
+    @Test
+    public void testCreateFileNode()
+    {
+        java.io.File file = new java.io.File(TEST_DIR, "text.txt");
+        FileUtilities.writeToFile(file, "hello");
+        INode node = NodeFactory.createNode(file);
+        assertTrue(node instanceof IFile);
+        assertEquals("text.txt", node.getName());
+    }
+    
+    @Test
+    public void testCreateDirectoryNode()
+    {
+        java.io.File file = new java.io.File(TEST_DIR, "dir");
+        file.mkdir();
+        INode node = NodeFactory.createNode(file);
+        assertTrue(node instanceof IDirectory);
+        assertEquals("dir", node.getName());
+    }
+}
diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/StringFile.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/StorageTestCase.java
similarity index 66%
rename from bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/StringFile.java
rename to bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/StorageTestCase.java
index 93976382f4970091c5cf0f4099c19793b899b05f..0e2b052ebd1fefbef18bd3433632df288facb2cb 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/StringFile.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/StorageTestCase.java
@@ -17,24 +17,25 @@
 package ch.systemsx.cisd.bds.storage.filesystem;
 
 import java.io.File;
+import java.io.IOException;
 
-import ch.systemsx.cisd.common.utilities.FileUtilities;
+import org.apache.commons.io.FileUtils;
+import org.testng.annotations.BeforeMethod;
 
 /**
  * 
  *
  * @author Franz-Josef Elmer
  */
-class StringFile extends AbstractFileNode<String>
+public class StorageTestCase
 {
-    StringFile(File file)
-    {
-        super(file);
-    }
+    static final File TEST_DIR = new File("targets" + File.separator + "unit-test-wd");
     
-    public String getValue()
+    @BeforeMethod
+    public void setup() throws IOException
     {
-        return FileUtilities.loadToString(nodeFile).trim();
+        TEST_DIR.mkdirs();
+        FileUtils.cleanDirectory(TEST_DIR);
     }
-
+    
 }