diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java
index a688984356108c3b69c448cb7a1e3e572dd5a73d..f15e6a73c5e77b368d22c0056838e123f10d0c88 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -38,6 +39,8 @@ import net.lemnik.eodsql.DataIterator;
 import org.apache.commons.lang.time.DateUtils;
 
 import ch.rinn.restrictions.Friend;
+import ch.systemsx.cisd.common.collections.IKeyExtractor;
+import ch.systemsx.cisd.common.collections.TableMap;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.types.BooleanOrUnknown;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.common.CodeRecord;
@@ -207,6 +210,105 @@ public class DatasetLister extends AbstractLister implements IDatasetLister
         return map;
     }
 
+    public Map<Long, Set<Long>> listChildrenIds(Collection<Long> dataSetIDs)
+    {
+        LongOpenHashSet ids = new LongOpenHashSet();
+        for (Long id : dataSetIDs)
+        {
+            ids.add(id);
+        }
+        DataIterator<DatasetRelationRecord> relationships = query.listChildrenDataSetIds(ids);
+        Map<Long, Set<Long>> map = new LinkedHashMap<Long, Set<Long>>();
+        for (DatasetRelationRecord relationship : relationships)
+        {
+            Set<Long> children = map.get(relationship.data_id_parent);
+            if (children == null)
+            {
+                children = new LinkedHashSet<Long>();
+                map.put(relationship.data_id_parent, children);
+            }
+            children.add(relationship.data_id_child);
+        }
+        return map;
+    }
+    
+    public Map<Sample, List<ExternalData>> listAllDataSetsFor(List<Sample> samples)
+    {
+        TableMap<Long, Sample> samplesByID =
+                new TableMap<Long, Sample>(samples, new IKeyExtractor<Long, Sample>()
+                    {
+                        public Long getKey(Sample e)
+                        {
+                            return e.getId();
+                        }
+                    });
+        Map<Sample, List<ExternalData>> result = new HashMap<Sample, List<ExternalData>>();
+        Set<Long> sampleIDs = new HashSet<Long>();
+        for (Sample sample : samples)
+        {
+            result.put(sample, new ArrayList<ExternalData>());
+            sampleIDs.add(sample.getId());
+        }
+        List<ExternalData> rootDataSets = listBySampleIds(sampleIDs);
+        addChildren(rootDataSets);
+        for (ExternalData dataSet : rootDataSets)
+        {
+            Sample sample = samplesByID.tryGet(dataSet.getSample().getId());
+            assert sample != null;
+            result.get(sample).add(dataSet);
+        }
+        return result;
+    }
+
+    private void addChildren(List<ExternalData> dataSets)
+    {
+        Map<Long, ExternalData> dataSetsByID = new HashMap<Long, ExternalData>();
+        for (ExternalData dataSet : dataSets)
+        {
+            dataSetsByID.put(dataSet.getId(), dataSet);
+        }
+        Map<Long, Set<Long>> childrenIDs = listChildrenIds(dataSetsByID.keySet());
+        Set<Entry<Long, Set<Long>>> entrySet = childrenIDs.entrySet();
+        Map<Long, Set<Long>> child2ParentsMap = new HashMap<Long, Set<Long>>();
+        Set<Long> childIDs = new HashSet<Long>();
+        for (Entry<Long, Set<Long>> entry : entrySet)
+        {
+            Set<Long> value = entry.getValue();
+            Long parentID = entry.getKey();
+            for (Long childId : value)
+            {
+                childIDs.add(childId);
+                Set<Long> parents = child2ParentsMap.get(childId);
+                if (parents == null)
+                {
+                    parents = new HashSet<Long>(1);
+                    child2ParentsMap.put(childId, parents);
+                }
+                parents.add(parentID);
+            }
+        }
+        if (childIDs.isEmpty() == false)
+        {
+            List<ExternalData> children = listByDatasetIds(childIDs);
+            for (ExternalData child : children)
+            {
+                Set<Long> parentIDs = child2ParentsMap.get(child.getId());
+                for (Long parentID : parentIDs)
+                {
+                    ExternalData dataSet = dataSetsByID.get(parentID);
+                    List<ExternalData> childList = dataSet.getChildren();
+                    if (childList == null)
+                    {
+                        childList = new ArrayList<ExternalData>(1);
+                        dataSet.setChildren(childList);
+                    }
+                    childList.add(child);
+                }
+            }
+            addChildren(children);
+        }
+    }
+
     public List<ExternalData> listByChildTechId(TechId childDatasetId)
     {
         return enrichDatasets(query.getParentDatasetsForChild(childDatasetId.getId()));
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetLister.java
index 02de40f08c6ca7dc66ccb53e43a46047fd22d47f..08583f96e0795169af042369465752e45dfc6e2b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetLister.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetLister.java
@@ -24,6 +24,7 @@ import java.util.Set;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ArchiverDataSetCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TrackingDataSetCriteria;
 
 /**
@@ -51,10 +52,22 @@ public interface IDatasetLister
 
     /**
      * Returns a map with all parent data set IDs of specified data set IDs. The keys of the map are
-     * IDs from the argument. A value of the map contains at least one alement.
+     * IDs from the argument. A value of the map contains at least one element.
      */
     Map<Long, Set<Long>> listParentIds(Collection<Long> dataSetIDs);
 
+    /**
+     * Returns a map with all child data set IDs of specified data set IDs. The keys of the map are
+     * IDs from the argument. A value of the map contains at least one element.
+     */
+    Map<Long, Set<Long>> listChildrenIds(Collection<Long> dataSetIDs);
+    
+    /**
+     * Returns a map with all data sets of specified samples. The sample arguments are the
+     * key into the returned map. The returned data sets contains all derived data sets (children,
+     * grand children, etc.).
+     */
+    Map<Sample, List<ExternalData>> listAllDataSetsFor(List<Sample> samples);
     //
 
     /** @return datasets with given ids */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetListingQuery.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetListingQuery.java
index e2263f2d02321ce6d519855891a1f2e496ff0325..aa67e7e955562bfd1a28ac626209c98050ad1923 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetListingQuery.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetListingQuery.java
@@ -109,6 +109,10 @@ public interface IDatasetListingQuery extends TransactionQuery, IPropertyListing
         { LongSetMapper.class }, fetchSize = FETCH_SIZE)
     public DataIterator<DatasetRelationRecord> listParentDataSetIds(LongSet ids);
 
+    @Select(sql = "select * from data_set_relationships where data_id_parent = any(?{1})", parameterBindings =
+        { LongSetMapper.class }, fetchSize = FETCH_SIZE)
+    public DataIterator<DatasetRelationRecord> listChildrenDataSetIds(LongSet ids);
+    
     /**
      * Returns all datasets that are children of any specified dataset id.
      */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java
index ac68f2bb0d5141e24428aea9c31f6d67b49d9025..13d9ad302f11bfb706e31c4732ec9873fd3391de 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.server.dataaccess;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
@@ -40,6 +41,12 @@ public interface IExperimentDAO extends IGenericDAO<ExperimentPE>
     public List<ExperimentPE> listExperimentsWithProperties(final ProjectPE projectOrNull)
             throws DataAccessException;
 
+    /**
+     * Lists experiments with specified ids. Fetches also properties. 
+     */
+    public List<ExperimentPE> listExperimentsWithProperties(final Collection<Long> experimentIDs)
+            throws DataAccessException;
+    
     /**
      * Lists experiments of specified type and specified project. Fetches also properties.
      * 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java
index afd7c9280500b519e48cb3967903a6ca949846dd..936cdd3682c68c2e5ca58523ced50debf2854bf7 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.openbis.generic.server.dataaccess.db;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
@@ -89,6 +90,22 @@ public class ExperimentDAO extends AbstractGenericEntityWithPropertiesDAO<Experi
         return list;
     }
 
+    public List<ExperimentPE> listExperimentsWithProperties(Collection<Long> experimentIDs)
+            throws DataAccessException
+    {
+        DetachedCriteria criteria = DetachedCriteria.forClass(getEntityClass());
+        criteria.add(Restrictions.in("id", experimentIDs));
+        criteria.setFetchMode("experimentProperties", FetchMode.JOIN);
+        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
+        final List<ExperimentPE> list = cast(getHibernateTemplate().findByCriteria(criteria));
+        if (operationLog.isDebugEnabled())
+        {
+            operationLog.debug(String.format("%d experiments have been found for specified IDs.",
+                    list.size()));
+        }
+        return list;
+    }
+
     public List<ExperimentPE> listExperiments() throws DataAccessException
     {
         final List<ExperimentPE> list = cast(getHibernateTemplate().loadAll(getEntityClass()));
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java
index e1272f4b4229132b1014ad0d90e5a9d2a7a9b44b..2ef33ef958ea8633a1d74662a925dab81eca3dd1 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java
@@ -18,11 +18,14 @@ package ch.systemsx.cisd.openbis.generic.server.business.bo.datasetlister;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertSame;
 
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -37,7 +40,9 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.common.entity.Seconda
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.AbstractDAOTest;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.translator.SampleTranslator;
 
 /**
  * @author Tomasz Pylak
@@ -90,4 +95,83 @@ public class DatasetListerTest extends AbstractDAOTest
         assertEquals("[2, 5, 6, 7]", list.toString());
     }
 
+    @Test
+    public void testListAllDataSetsFor()
+    {
+        HashSet<String> samplePermIDs =
+                new HashSet<String>(Arrays.asList("200811050946559-983", "200902091219327-1025"));
+        List<SamplePE> samplePEs = daoFactory.getSampleDAO().listByPermID(samplePermIDs);
+        List<Sample> samples = SampleTranslator.translate(samplePEs, "");
+        
+        Map<Sample, List<ExternalData>> dataSets = lister.listAllDataSetsFor(samples);
+        
+        StringBuilder builder = new StringBuilder();
+        for (Sample sample : samples)
+        {
+            builder.append(sample.getCode());
+            appendChildren(builder, dataSets.get(sample), "   ");
+            builder.append('\n');
+        }
+        assertEquals("3VCP1\n   20081105092158673-1 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "     20081105092159188-3 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "     20081105092259000-9 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "       20081105092259900-0 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "         20081105092359990-2 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "       20081105092259900-1 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "         20081105092359990-2 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "CP-TEST-1\n"
+                + "   20081105092159111-1 (HCS_IMAGE) [ANY_MATERIAL: 1000_C (SIRNA), "
+                + "BACTERIUM: BACTERIUM1 (BACTERIUM), COMMENT: no comment, GENDER: FEMALE]\n"
+                + "     20081105092259000-9 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "       20081105092259900-0 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "         20081105092359990-2 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "       20081105092259900-1 (HCS_IMAGE) [COMMENT: no comment]\n"
+                + "         20081105092359990-2 (HCS_IMAGE) [COMMENT: no comment]\n",
+                builder.toString());
+        Map<String, ExternalData> dataSetsByCode = new HashMap<String, ExternalData>();
+        for (Sample sample : samples)
+        {
+            List<ExternalData> rootDataSets = dataSets.get(sample);
+            assertSameDataSetsForSameCode(dataSetsByCode, rootDataSets);
+        }
+    }
+
+    private void assertSameDataSetsForSameCode(Map<String, ExternalData> dataSetsByCode,
+            List<ExternalData> dataSets)
+    {
+        if (dataSets == null || dataSets.isEmpty())
+        {
+            return;
+        }
+        for (ExternalData dataSet : dataSets)
+        {
+            ExternalData previousDataSet = dataSetsByCode.put(dataSet.getCode(), dataSet);
+            if (previousDataSet != null)
+            {
+                assertSame("Same data set object expected for " + dataSet.getCode(), previousDataSet,
+                        dataSet);
+            }
+            List<ExternalData> children = dataSet.getChildren();
+            assertSameDataSetsForSameCode(dataSetsByCode, children);
+        }
+    }
+
+    private void appendChildren(StringBuilder builder, List<ExternalData> dataSets,
+            String indentation)
+    {
+        if (dataSets.isEmpty() == false)
+        {
+            for (ExternalData dataSet : dataSets)
+            {
+                builder.append('\n').append(indentation).append(dataSet.getCode()).append(" (");
+                builder.append(dataSet.getDataSetType().getCode()).append(") ");
+                builder.append(getSortedProperties(dataSet));
+                List<ExternalData> children = dataSet.getChildren();
+                if (children != null && children.isEmpty() == false)
+                {
+                    appendChildren(builder, children, indentation + "  ");
+                }
+            }
+        }
+    }
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AbstractDAOWithoutContextTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AbstractDAOWithoutContextTest.java
index c1837492d1ef25fb0e1121f6b24950ae3d1dec60..29e981a8782283b7d180ba26156cfaccb6d9e25f 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AbstractDAOWithoutContextTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AbstractDAOWithoutContextTest.java
@@ -22,6 +22,7 @@ import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
 
@@ -41,6 +42,8 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExternalDataDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.HibernateSearchContext;
 import ch.systemsx.cisd.openbis.generic.server.util.TestInitializer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataTypeCode;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityPropertiesHolder;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.dto.AuthorizationGroupPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Code;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataTypePE;
@@ -362,4 +365,17 @@ public abstract class AbstractDAOWithoutContextTest extends
         result.setRegistrator(getSystemPerson());
         return result;
     }
+
+    protected List<IEntityProperty> getSortedProperties(IEntityPropertiesHolder sample)
+    {
+        List<IEntityProperty> properties = sample.getProperties();
+        Collections.sort(properties, new Comparator<IEntityProperty>()
+            {
+                public int compare(IEntityProperty p1, IEntityProperty p2)
+                {
+                    return p1.getPropertyType().getCode().compareTo(p2.getPropertyType().getCode());
+                }
+            });
+        return properties;
+    }
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java
index 7b13d6e5a6d6ff6202c75b2c20cb2f9a2b81174b..5eedb302435de1d880853d4efad1bda44785f532 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java
@@ -32,11 +32,11 @@ public class TestInitializer
         LogInitializer.init();
         System.setProperty("database.create-from-scratch", "true");
         System.setProperty("database.kind", "test");
-        System.setProperty("script-folder", "sourceTest");
+        System.setProperty("script-folder", "../openbis/sourceTest");
         System.setProperty("hibernate.search.index-mode", "NO_INDEX");
         System.setProperty("hibernate.search.index-base", LUCENE_INDEX_PATH);
         System.setProperty("hibernate.search.worker.execution", "sync");
-        System.setProperty("mass-upload-folder", "sourceTest/sql/postgresql");
+        System.setProperty("mass-upload-folder", "../openbis/sourceTest/sql/postgresql");
     }
 
 }