diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/ImageMetadataExtractor.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/ImageMetadataExtractor.java
index e9fa775a4aa17aa563d3488e8bc9ec27cf6c4320..b0383e3b7894d269fc078ce0be41b8c893306e08 100644
--- a/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/ImageMetadataExtractor.java
+++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/ImageMetadataExtractor.java
@@ -20,15 +20,8 @@ import java.io.File;
 import java.util.HashMap;
 import java.util.Map;
 
-import ch.systemsx.cisd.cina.shared.labview.Cluster;
-import ch.systemsx.cisd.cina.shared.labview.DBL;
-import ch.systemsx.cisd.cina.shared.labview.EW;
 import ch.systemsx.cisd.cina.shared.labview.LVData;
-import ch.systemsx.cisd.cina.shared.labview.LVDataBoolean;
 import ch.systemsx.cisd.cina.shared.labview.LVDataParser;
-import ch.systemsx.cisd.cina.shared.labview.LVDataString;
-import ch.systemsx.cisd.cina.shared.labview.U32;
-import ch.systemsx.cisd.cina.shared.labview.U8;
 
 /**
  * Class for extracting the metadata from a folder containing an image + metadata.
@@ -37,7 +30,7 @@ import ch.systemsx.cisd.cina.shared.labview.U8;
  */
 public class ImageMetadataExtractor
 {
-    private final Map<String, String> metadataMap;
+    private final HashMap<String, String> metadataMap;
 
     private final File folder;
 
@@ -53,33 +46,47 @@ public class ImageMetadataExtractor
         prefixMap.put("Image dimension (px)", "Dimension");
     }
 
+    public static boolean doesFolderContainImageMetadata(File folder)
+    {
+        File metadataFile = new File(folder, METADATA_FILE_NAME);
+        return metadataFile.exists();
+    }
+
     /**
      * Create an image metadata with a parent metadata.
      * 
-     * @param parentMetadata The inherited parent metadata
+     * @param parentMetadataOrNull The inherited parent metadata or null if there is none
      * @param folder The folder containing the metadata
      */
-    public ImageMetadataExtractor(Map<String, String> parentMetadata, File folder)
+    public ImageMetadataExtractor(Map<String, String> parentMetadataOrNull, File folder)
     {
-        this.metadataMap = new HashMap<String, String>(parentMetadata);
+
+        this.metadataMap =
+                (null != parentMetadataOrNull) ? new HashMap<String, String>(parentMetadataOrNull)
+                        : new HashMap<String, String>();
         this.folder = folder;
     }
 
     /**
-     * Get the metadata extracted from the file in the form of a hash map. Parse must be called
-     * before getting the metadata.
+     * Read the files and fill the metadata map.
+     * 
+     * @throws IllegalArgumentException If there is not metadata.xml file in the folder or if the
+     *             file is faulty.
      */
-    public Map<String, String> getMetadataMap()
+    public void prepare() throws IllegalArgumentException
     {
-        assert lvdata != null;
-        return metadataMap;
-    }
+        if (null != lvdata)
+        {
+            // We've already parsed this
+            return;
+        }
+
+        if (false == doesFolderContainImageMetadata(folder))
+        {
+            throw new IllegalArgumentException("Folder " + folder
+                    + " is not an image metadata file");
+        }
 
-    /**
-     * Parse the metadata file.
-     */
-    public void parse()
-    {
         File metadataFile = new File(folder, METADATA_FILE_NAME);
         lvdata = LVDataParser.parse(metadataFile);
         if (null == lvdata)
@@ -88,56 +95,21 @@ public class ImageMetadataExtractor
                     + metadataFile.getAbsolutePath());
         }
 
-        if (1 != lvdata.getClusters().size())
-        {
-            throw new IllegalArgumentException("Parser expects only one cluster in file "
-                    + metadataFile.getAbsolutePath() + "; Found " + lvdata.getClusters().size());
-        }
-
-        Cluster cluster = lvdata.getClusters().get(0);
-        parseCluster(cluster, "");
+        new LabViewXMLToHashMap(lvdata, metadataMap, prefixMap).appendIntoMap();
     }
 
-    private void parseCluster(Cluster cluster, String prefix)
+    /**
+     * Get the metadata extracted from the file in the form of a map. The method {@link #prepare}
+     * must be called before getting the metadata map.
+     */
+    public Map<String, String> getMetadataMap()
     {
-        for (LVDataString lvdataString : cluster.getStrings())
-        {
-            metadataMap.put(prefix + lvdataString.getName(), lvdataString.getValue());
-        }
-
-        for (U8 u8 : cluster.getU8s())
-        {
-            metadataMap.put(prefix + u8.getName(), u8.getValue().toString());
-        }
-
-        for (U32 u32 : cluster.getU32s())
-        {
-            metadataMap.put(prefix + u32.getName(), u32.getValue().toString());
-        }
-
-        for (DBL dbl : cluster.getDbls())
-        {
-            metadataMap.put(prefix + dbl.getName(), dbl.getValue().toString());
-        }
-
-        for (LVDataBoolean bool : cluster.getBooleans())
-        {
-            metadataMap.put(prefix + bool.getName(), bool.getValue().toString());
-        }
-
-        for (EW ew : cluster.getEws())
-        {
-            metadataMap.put(prefix + ew.getName(), ew.getChosenValue());
-        }
+        checkPrepared();
+        return metadataMap;
+    }
 
-        for (Cluster subcluster : cluster.getClusters())
-        {
-            String clusterPrefix = prefixMap.get(subcluster.getName());
-            if (null == clusterPrefix)
-            {
-                clusterPrefix = "";
-            }
-            parseCluster(subcluster, clusterPrefix);
-        }
+    private void checkPrepared()
+    {
+        assert lvdata != null;
     }
 }
diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/LabViewXMLToHashMap.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/LabViewXMLToHashMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..f654da0607f334e73337045984ef1d433d606800
--- /dev/null
+++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/LabViewXMLToHashMap.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.cina.shared.metadata;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import ch.systemsx.cisd.cina.shared.labview.Cluster;
+import ch.systemsx.cisd.cina.shared.labview.DBL;
+import ch.systemsx.cisd.cina.shared.labview.EW;
+import ch.systemsx.cisd.cina.shared.labview.LVData;
+import ch.systemsx.cisd.cina.shared.labview.LVDataBoolean;
+import ch.systemsx.cisd.cina.shared.labview.LVDataString;
+import ch.systemsx.cisd.cina.shared.labview.U32;
+import ch.systemsx.cisd.cina.shared.labview.U8;
+
+/**
+ * Helper class for converting the content of a LabView XML file into a HashMap.
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+class LabViewXMLToHashMap
+{
+    private final LVData lvdata;
+
+    private final Map<String, String> metadataMap;
+
+    private final Map<String, String> prefixMap;
+
+    /**
+     * Constructor for converting lvdata into the metadataMap
+     * 
+     * @param lvdata The XML Data
+     * @param metadataMap The HashMap to append the converted content into
+     */
+    LabViewXMLToHashMap(LVData lvdata, Map<String, String> metadataMap)
+    {
+        this(lvdata, metadataMap, new HashMap<String, String>());
+    }
+
+    /**
+     * Constructor for converting lvdata into the metadataMap, specifying a mapping from cluster
+     * prefixes to key prefixes
+     * 
+     * @param lvdata The XML Data
+     * @param metadataMap The map to append the converted content into
+     * @param prefixMap A map from cluster names to prefix names for keys in the resulting hash map
+     */
+    public LabViewXMLToHashMap(LVData lvdata, Map<String, String> metadataMap,
+            Map<String, String> prefixMap)
+    {
+        this.lvdata = lvdata;
+        this.metadataMap = metadataMap;
+        this.prefixMap = prefixMap;
+    }
+
+    public void appendIntoMap()
+    {
+        for (Cluster cluster : lvdata.getClusters())
+        {
+            parseCluster(cluster, getClusterPrefix(cluster));
+        }
+    }
+
+    private void parseCluster(Cluster cluster, String prefix)
+    {
+        for (LVDataString lvdataString : cluster.getStrings())
+        {
+            metadataMap.put(prefix + lvdataString.getName(), lvdataString.getValue());
+        }
+
+        for (U8 u8 : cluster.getU8s())
+        {
+            metadataMap.put(prefix + u8.getName(), u8.getValue().toString());
+        }
+
+        for (U32 u32 : cluster.getU32s())
+        {
+            metadataMap.put(prefix + u32.getName(), u32.getValue().toString());
+        }
+
+        for (DBL dbl : cluster.getDbls())
+        {
+            metadataMap.put(prefix + dbl.getName(), dbl.getValue().toString());
+        }
+
+        for (LVDataBoolean bool : cluster.getBooleans())
+        {
+            metadataMap.put(prefix + bool.getName(), bool.getValue().toString());
+        }
+
+        for (EW ew : cluster.getEws())
+        {
+            metadataMap.put(prefix + ew.getName(), ew.getChosenValue());
+        }
+
+        for (Cluster subcluster : cluster.getClusters())
+        {
+            parseCluster(subcluster, getClusterPrefix(subcluster));
+        }
+    }
+
+    private String getClusterPrefix(Cluster cluster)
+    {
+        String clusterPrefix = prefixMap.get(cluster.getName());
+        if (null == clusterPrefix)
+        {
+            clusterPrefix = "";
+        }
+        return clusterPrefix;
+    }
+}
diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/ReplicaMetadataExtractor.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/ReplicaMetadataExtractor.java
index 227930fcb776f03e0bc32ca40d5024234aec3909..8eecdd4cf5ab6fba080a9edce9639cf2079d6352 100644
--- a/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/ReplicaMetadataExtractor.java
+++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/shared/metadata/ReplicaMetadataExtractor.java
@@ -16,23 +16,122 @@
 
 package ch.systemsx.cisd.cina.shared.metadata;
 
-//import java.io.File;
-//import java.util.ArrayList;
-//import java.util.List;
-//import java.util.Map;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ch.systemsx.cisd.cina.shared.labview.LVData;
+import ch.systemsx.cisd.cina.shared.labview.LVDataParser;
 
 /**
  * @author Chandrasekhar Ramakrishnan
  */
 public class ReplicaMetadataExtractor
 {
-    // private final List<Map<String, String>> metadata;
-    //
-    // private final File folder;
-    //
-    // public ReplicaMetadataExtractor()
-    // {
-    // metadata = new ArrayList<Map<String, String>>();
-    // folder = null;
-    // }
+    private final ArrayList<ImageMetadataExtractor> metadataExtractors;
+
+    private final File folder;
+
+    private final HashMap<String, String> metadataMap;
+
+    private LVData lvdata;
+
+    private static final String METADATA_FILE_NAME = "ReplicaMetadata.xml";
+
+    public ReplicaMetadataExtractor(File folder)
+    {
+        metadataExtractors = new ArrayList<ImageMetadataExtractor>();
+        this.folder = folder;
+        this.metadataMap = new HashMap<String, String>();
+    }
+
+    /**
+     * Read the files and fill the metadata map.
+     */
+    public void prepare()
+    {
+        if (null != lvdata)
+        {
+            // We've already parsed this
+            return;
+        }
+
+        // Firse parse the metadata for the replica
+        File metadataFile = new File(folder, METADATA_FILE_NAME);
+        lvdata = LVDataParser.parse(metadataFile);
+        if (null == lvdata)
+        {
+            throw new IllegalArgumentException("Could not parse metadata in file "
+                    + metadataFile.getAbsolutePath());
+        }
+
+        new LabViewXMLToHashMap(lvdata, metadataMap).appendIntoMap();
+
+        // Then get the image metadata
+        File[] replicaContents = folder.listFiles();
+        for (File replicaFile : replicaContents)
+        {
+            if (false == replicaFile.isDirectory())
+            {
+                continue;
+            }
+
+            // The folders containing the metadata are two levels down
+            File[] imageContents = replicaFile.listFiles();
+            for (File imageFolder : imageContents)
+            {
+                if (false == imageFolder.isDirectory())
+                {
+                    continue;
+                }
+
+                processDirectory(imageFolder);
+            }
+        }
+    }
+
+    /**
+     * Get the metadata extracted from the file in the form of a map. The method {@link #prepare}
+     * must be called before getting the metadata map.
+     */
+    public Map<String, String> getMetadataMap()
+    {
+        checkPrepared();
+        return metadataMap;
+    }
+
+    /**
+     * Get the metadata extractors for each of the image files for this replica. The method
+     * {@link #prepare} must be called before getting the metadata extractors.
+     */
+    public List<ImageMetadataExtractor> getMetadataExtractors()
+    {
+        checkPrepared();
+        return metadataExtractors;
+    }
+
+    private void checkPrepared()
+    {
+        assert lvdata != null;
+    }
+
+    private void processDirectory(File file)
+    {
+        if (false == file.isDirectory())
+        {
+            return;
+        }
+
+        if (false == ImageMetadataExtractor.doesFolderContainImageMetadata(file))
+        {
+            return;
+        }
+
+        ImageMetadataExtractor imageMetadataExtractor = new ImageMetadataExtractor(null, file);
+        imageMetadataExtractor.prepare();
+
+        metadataExtractors.add(imageMetadataExtractor);
+    }
 }