diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/EntitiesFinder.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/EntitiesFinder.java
index 93599afa034a8b8e014915160bfbb9b7db76b29e..74cba6fac81838d003bbfd8bde8f6362168b50ea 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/EntitiesFinder.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/EntitiesFinder.java
@@ -214,6 +214,7 @@ class EntitiesFinder
         fetchOptions.withRegistrator();
         fetchOptions.withModifier();
         fetchOptions.withDataSets();
+        fetchOptions.withContainer();
         return api.getSamples(sessionToken, samplePermIds, fetchOptions).values();
     }
 
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/ExportExecutor.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/ExportExecutor.java
index ab2aff3d40ac306d408c367448c2d987ac62a974..27df4ad8b89c7a71c91b96e27c90a77762d5638b 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/ExportExecutor.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/ExportExecutor.java
@@ -44,6 +44,7 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FilenameFilter;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
@@ -131,7 +132,11 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space;
 import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.NotFetchedException;
 import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile;
+import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownload;
+import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions;
+import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadReader;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.fetchoptions.DataSetFileFetchOptions;
+import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.DataSetFilePermId;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.search.DataSetFileSearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
@@ -227,8 +232,6 @@ public class ExportExecutor implements IExportExecutor
     @Autowired
     private ISessionWorkspaceProvider sessionWorkspaceProvider;
 
-//    private IDataStoreServerApi v3Dss = (IDataStoreServerApi) ServiceProvider.getDssServiceV3().getService();
-
     @Resource(name = ExposablePropertyPlaceholderConfigurer.PROPERTY_CONFIGURER_BEAN_NAME)
     private ExposablePropertyPlaceholderConfigurer configurer;
 
@@ -369,6 +372,7 @@ public class ExportExecutor implements IExportExecutor
         for (final Sample sample : samples)
         {
             final List<DataSet> dataSets = sample.getDataSets();
+            final Sample container = sample.getContainer();
 
             for (final DataSet dataSet : dataSets)
             {
@@ -382,18 +386,49 @@ public class ExportExecutor implements IExportExecutor
 
                     OPERATION_LOG.info(String.format("Found: %d files", results.getTotalCount()));
 
-                    for (final DataSetFile file : results.getObjects())
+                    final List<DataSetFile> dataSetFiles = results.getObjects();
+                    final List<DataSetFilePermId> fileIds = dataSetFiles.stream().map(DataSetFile::getPermId).collect(Collectors.toList());
+
+                    final DataSetFileDownloadOptions options = new DataSetFileDownloadOptions();
+                    options.setRecursive(true);
+
+                    final InputStream stream = v3Dss.downloadFiles(sessionToken, fileIds, options);
+                    final DataSetFileDownloadReader reader = new DataSetFileDownloadReader(stream);
+
+                    DataSetFileDownload file;
+                    while ((file = reader.read()) != null)
                     {
-                        final String filePath = file.getPath();
-                        final Sample container = sample.getContainer();
-                        putNextDataZipEntry(existingZipEntries, zos, 'S', getSpaceCode(sample), getProjectCode(SAMPLE),
-                                container == null ? null : container.getCode(), sample.getCode(), getEntityName(sample), getFileName(filePath));
+                        final DataSetFile dataSetFile = file.getDataSetFile();
+                        final String filePath = dataSetFile.getPath();
+//                        putNextDataZipEntry(existingZipEntries, zos, 'O', getSpaceCode(sample), getProjectCode(sample),
+//                                container == null ? null : container.getCode(), sample.getCode(), getEntityName(sample), getFileName(filePath));
 
-                        if (!file.isDirectory())
+                        if (!dataSetFile.isDirectory())
                         {
-                            // TODO: add content
+                            try (final InputStream is = file.getInputStream())
+                            {
+                                writeInChunks(bos, is);
+                            }
                         }
                     }
+
+//                    for (final DataSetFile dataSetFile : dataSetFiles)
+//                    {
+//                        final String filePath = dataSetFile.getPath();
+//                        final Sample container = sample.getContainer();
+//                        putNextDataZipEntry(existingZipEntries, zos, 'O', getSpaceCode(sample), getProjectCode(sample),
+//                                container == null ? null : container.getCode(), sample.getCode(), getEntityName(sample), getFileName(filePath));
+//
+//                        v3Dss.downloadFiles(sessionToken, )
+//
+//                        if (!dataSetFile.isDirectory())
+//                        {
+//                            try (final FileInputStream fis = new FileInputStream(filePath))
+//                            {
+//                                writeInChunks(bos, fis);
+//                            }
+//                        }
+//                    }
                 } else
                 {
                     OPERATION_LOG.info(String.format("Omitted data export for link dataset with permId: %s", dataSetPermId));
@@ -824,6 +859,17 @@ public class ExportExecutor implements IExportExecutor
         os.flush();
     }
 
+    private static void writeInChunks(final OutputStream os, final InputStream is) throws IOException
+    {
+        final byte[] buffer = new byte[BUFFER_SIZE];
+        int length;
+        while ((length = is.read(buffer)) > 0)
+        {
+            os.write(buffer, 0, length);
+        }
+        os.flush();
+    }
+
     /**
      * Adds an entry only if it is needed.
      *
@@ -863,7 +909,8 @@ public class ExportExecutor implements IExportExecutor
             entryBuilder.append('/').append(projectCode);
             if (experimentCode != null)
             {
-                addFullEntityName(entryBuilder, experimentCode, experimentName);
+                entryBuilder.append('/');
+                addFullEntityName(entryBuilder, null, experimentCode, experimentName);
 
                 if (sampleCode == null && dataSetCode != null)
                 {
@@ -881,7 +928,8 @@ public class ExportExecutor implements IExportExecutor
 
         if (sampleCode != null)
         {
-            addFullEntityName(entryBuilder, sampleCode, sampleName);
+            entryBuilder.append('/');
+            addFullEntityName(entryBuilder, containerCode, sampleCode, sampleName);
 
             if (dataSetCode != null)
             {
@@ -896,10 +944,11 @@ public class ExportExecutor implements IExportExecutor
 
     private static void putNextDataZipEntry(final Set<String> existingZipEntries, final ZipOutputStream zos, final char prefix,
             final String spaceCode, final String projectCode, final String containerCode, final String entityCode, final String entityName,
-            final String fileName)
+            final String dataSetTypeCode, final String dataSetCode, final String dataSetName, final String fileName)
             throws IOException
     {
-        final String entry = getFolderName(prefix, spaceCode, projectCode, containerCode, entityCode, entityName);
+        final String entry = getFolderName(prefix, spaceCode, projectCode, containerCode, entityCode, dataSetTypeCode, dataSetCode,
+                dataSetName, fileName);
         if (!existingZipEntries.contains(entry))
         {
             zos.putNextEntry(new ZipEntry(entry));
@@ -908,11 +957,17 @@ public class ExportExecutor implements IExportExecutor
     }
 
     static String getFolderName(final char prefix, final String spaceCode, final String projectCode,
-            final String containerCode, final String entityCode, final String entityName)
+            final String containerCode, final String entityCode, final String dataSetTypeCode,
+            final String dataSetCode, final String dataSetName, final String fileName)
     {
         if (prefix != 'O' && prefix != 'E')
         {
-            throw new IllegalArgumentException("Only 'O' and 'E' can be used as prefix.");
+            throw new IllegalArgumentException(String.format("Only 'O' and 'E' can be used as prefix got '%c' instead.", prefix));
+        }
+
+        if (containerCode != null && prefix != 'O')
+        {
+            throw new IllegalArgumentException("Only objects can have containers.");
         }
 
         final StringBuilder entryBuilder = new StringBuilder(String.valueOf(prefix));
@@ -936,46 +991,64 @@ public class ExportExecutor implements IExportExecutor
             throw new IllegalArgumentException("Project code cannot be null for experiments.");
         }
 
-        entryBuilder.append('+');
+        if (entityCode != null)
+        {
+            entryBuilder.append('+');
+            addFullEntityCode(entryBuilder, containerCode, entityCode);
+        } else
+        {
+            throw new IllegalArgumentException("Entity code is mandatory");
+        }
 
-        if (containerCode != null)
+        if (dataSetTypeCode != null)
         {
-            if (prefix == 'O')
-            {
-                entryBuilder.append(containerCode).append('*');
-            } else
-            {
-                throw new IllegalArgumentException("Only objects can have containers.");
-            }
+            entryBuilder.append('+').append(dataSetTypeCode);
+        } else
+        {
+            throw new IllegalArgumentException("Data set type code is mandatory");
         }
 
-        if (entityCode != null)
+        if (dataSetCode != null)
         {
-            entryBuilder.append(entityCode);
+            entryBuilder.append('+');
+            addFullEntityName(entryBuilder, null, dataSetCode, dataSetName);
         } else
         {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("Data set code is mandatory");
         }
 
-        if (entityName != null)
+        if (fileName != null)
         {
-            entryBuilder.append('+').append(entityName);
+            entryBuilder.append('/').append(fileName);
         }
 
         return entryBuilder.toString();
     }
 
-    private static void addFullEntityName(final StringBuilder entryBuilder, final String entityCode, final String entityName)
+    private static void addFullEntityName(final StringBuilder entryBuilder, final String containerCode, final String entityCode,
+            final String entityName)
     {
         if (entityName == null || entityName.isEmpty())
         {
-            entryBuilder.append("/").append(entityCode);
+            addFullEntityCode(entryBuilder, containerCode, entityCode);
         } else
         {
-            entryBuilder.append("/").append(entityName).append(" (").append(entityCode).append(")");
+            entryBuilder.append(entityName).append(" (");
+            addFullEntityCode(entryBuilder, containerCode, entityCode);
+            entryBuilder.append(")");
         }
     }
 
+    private static void addFullEntityCode(final StringBuilder entryBuilder, final String containerCode, final String entityCode)
+    {
+        if (containerCode != null)
+        {
+            entryBuilder.append(containerCode).append('*');
+        }
+
+        entryBuilder.append(entityCode);
+    }
+
     private static String getEntityName(final IPropertiesHolder entity)
     {
         try
@@ -989,7 +1062,7 @@ public class ExportExecutor implements IExportExecutor
 
     static String escapeUnsafeCharacters(final String name)
     {
-        return name.replaceAll(UNSAFE_CHARACTERS_REGEXP, "_");
+        return name != null ? name.replaceAll(UNSAFE_CHARACTERS_REGEXP, "_") : null;
     }
 
     private static void exportXls(final ZipOutputStream zos, final BufferedOutputStream bos, final XLSExport.PrepareWorkbookResult xlsExportResult,
diff --git a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServiceProvider.java b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServiceProvider.java
index 95ec68f22ddd29091379c8fb9ade5ea05dc73421..4dbede8a54b57d1100ceb7168c5568883b593c1c 100644
--- a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServiceProvider.java
+++ b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServiceProvider.java
@@ -55,7 +55,14 @@ public class CommonServiceProvider
 
     public static void setDataStoreServerApi(final String dssURL, final int timeoutInMinutes)
     {
-        dataStoreServerApi = HttpInvokerUtils.createServiceStub(IDataStoreServerApi.class, dssURL + IDataStoreServerApi.SERVICE_URL, timeoutInMinutes * 60 * 1000);
+        dataStoreServerApi = HttpInvokerUtils.createServiceStub(IDataStoreServerApi.class, dssURL +
+                        "/datastore_server" + IDataStoreServerApi.SERVICE_URL,
+                timeoutInMinutes * 60 * 1000);
+    }
+
+    public static void setDataStoreServerApi(final IDataStoreServerApi dataStoreServerApi)
+    {
+        CommonServiceProvider.dataStoreServerApi = dataStoreServerApi;
     }
 
     public static ICommonServerForInternalUse getCommonServer()
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/ExportExecutorTest.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/ExportExecutorTest.java
index e47d75c2c7974416cb4fd25d00a44bf2c9b7fc27..3d11d380a7dea5fe49f31760e46d43428b0cbd41 100644
--- a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/ExportExecutorTest.java
+++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/exporter/ExportExecutorTest.java
@@ -237,57 +237,80 @@ public class ExportExecutorTest
 
     private static final Object[][] FOLDER_NAME_DATA = {
             {
-                    'O', "SPACE", "PROJECT", null, "CODE_A", "NAME_A", "O+SPACE+PROJECT+CODE_A+NAME_A"
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "OBJ1", "ANALYZED_DATA", "AD_1", "my dataset", null,
+                    "O+DEFAULT_LAB_NOTEBOOK+DEFAULT_PROJECT+OBJ1+ANALYZED_DATA+my dataset (AD_1)"
             },
             {
-                    'O', "SPACE", null, null, "CODE_A", "NAME_A", "O+SPACE+CODE_A+NAME_A"
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "OBJ1", "ANALYZED_DATA", "AD_1", "my dataset", "file",
+                    "O+DEFAULT_LAB_NOTEBOOK+DEFAULT_PROJECT+OBJ1+ANALYZED_DATA+my dataset (AD_1)/file"
             },
             {
-                    'O', null, null, null, "CODE_A", "NAME_A", "O+CODE_A+NAME_A"
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "OBJ1", "ANALYZED_DATA", "AD_1", null, "file",
+                    "O+DEFAULT_LAB_NOTEBOOK+DEFAULT_PROJECT+OBJ1+ANALYZED_DATA+AD_1/file"
             },
             {
-                    'E', "SPACE", "PROJECT", null, "CODE_A", null, "E+SPACE+PROJECT+CODE_A"
+                    'O', "DEFAULT_LAB_NOTEBOOK", null, null, "OBJ1", "ANALYZED_DATA", "AD_1", "my dataset", "file",
+                    "O+DEFAULT_LAB_NOTEBOOK+OBJ1+ANALYZED_DATA+my dataset (AD_1)/file"
             },
             {
-                    'O', "SPACE", "PROJECT", "CODE_B", "CODE_A", "NAME_A", "O+SPACE+PROJECT+CODE_B*CODE_A+NAME_A"
+                    'O', "DEFAULT_LAB_NOTEBOOK", null, null, "OBJ1", "ANALYZED_DATA", "AD_1", null, "file",
+                    "O+DEFAULT_LAB_NOTEBOOK+OBJ1+ANALYZED_DATA+AD_1/file"
+            },
+            {
+                    'O', null, null, null, "OBJ1", "ANALYZED_DATA", "AD_1", "my dataset", "file",
+                    "O+OBJ1+ANALYZED_DATA+my dataset (AD_1)/file"
+            },
+            {
+                    'O', null, null, null, "OBJ1", "ANALYZED_DATA", "AD_1", null, "file",
+                    "O+OBJ1+ANALYZED_DATA+AD_1/file"
+            },
+            {
+                    'E', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "EXP1", "ANALYZED_DATA", "AD_1", "my dataset", "file",
+                    "E+DEFAULT_LAB_NOTEBOOK+DEFAULT_PROJECT+EXP1+ANALYZED_DATA+my dataset (AD_1)/file"
+            },
+            {
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", "OBJ_CONTAINER", "OBJ1", "ANALYZED_DATA", "AD_1", "my dataset", "file",
+                    "O+DEFAULT_LAB_NOTEBOOK+DEFAULT_PROJECT+OBJ_CONTAINER*OBJ1+ANALYZED_DATA+my dataset (AD_1)/file"
             },
     };
 
     private static final Object[][] ERRONEOUS_FOLDER_NAME_DATA = {
             {
-                    'P', "SPACE", "PROJECT", null, "CODE_A", "NAME_A"
+                    'P', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "OBJ1", "ANALYZED_DATA", "AD_1", "my dataset", "file"
             },
             {
-                    'O', null, "PROJECT", null, "CODE_A", "NAME_A"
+                    'O', null, "DEFAULT_PROJECT", null, "OBJ1", "ANALYZED_DATA", "AD_1", "my dataset", "file"
             },
             {
-                    'O', "SPACE", "PROJECT", null, null, "NAME_A"
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, null, "ANALYZED_DATA", "AD_1", "my dataset", "file"
             },
             {
-                    'O', "SPACE", "PROJECT", null, null, null
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", "OBJ_CONTAINER", null, "ANALYZED_DATA", "AD_1", "my dataset", "file"
             },
             {
-                    'O', "SPACE", "PROJECT", "CODE_B", null, "NAME_A"
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "OBJ1", null, "AD_1", "my dataset", "file"
             },
             {
-                    'O', "SPACE", "PROJECT", "CODE_B", null, null
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "OBJ1", "ANALYZED_DATA", null, "my dataset", "file"
             },
-
             {
-                    // Experiments cannot have containers
-                    'E', "SPACE", "PROJECT", "CODE_B", "CODE_A", null
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "OBJ1", "ANALYZED_DATA", null, null, "file"
             },
+            {
+                    'O', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", null, "OBJ1", "ANALYZED_DATA", null, null, null
+            },
+
             {
                     // Experiments cannot have containers
-                    'E', "SPACE", "PROJECT", "CODE_B", "CODE_A", "NAME_A"
+                    'E', "DEFAULT_LAB_NOTEBOOK", "DEFAULT_PROJECT", "EXP_CONTAINER", "EXP1", "ANALYZED_DATA", "AD_1", "my dataset", "file"
             },
             {
                     // Experiments cannot be on the space level
-                    'E', "SPACE", null, null, "CODE_A", "NAME_A"
+                    'E', "DEFAULT_LAB_NOTEBOOK", null, null, "EXP1", "ANALYZED_DATA", "AD_1", "my dataset", "file"
             },
             {
-                    // Experiments cannot be standalone
-                    'E', null, null, null, "CODE_A", "NAME_A"
+                    // Experiments cannot be shared (w/o space)
+                    'E', null, null, null, "EXP1", "ANALYZED_DATA", "AD_1", "my dataset", "file"
             },
     };
 
@@ -334,17 +357,19 @@ public class ExportExecutorTest
 
     @Test(dataProvider = FOLDER_NAME_DATA_PROVIDER)
     public void testGetFolderName(final char prefix, final String spaceCode, final String projectCode,
-            final String containerCode, final String entityCode, final String entityName, final String expectedResult)
+            final String containerCode, final String entityCode, final String dataSetTypeCode, final String dataSetCode,
+            final String dataSetName, final String fileName, final String expectedResult)
     {
-        assertEquals(ExportExecutor.getFolderName(prefix, spaceCode, projectCode, containerCode, entityCode, entityName),
-                expectedResult);
+        assertEquals(ExportExecutor.getFolderName(prefix, spaceCode, projectCode, containerCode, entityCode, dataSetTypeCode, dataSetCode,
+                dataSetName, fileName), expectedResult);
     }
 
     @Test(dataProvider = ERRONEOUS_FOLDER_NAME_DATA_PROVIDER, expectedExceptions = IllegalArgumentException.class)
     public void testGetFolderNameError(final char prefix, final String spaceCode, final String projectCode,
-            final String containerCode, final String entityCode, final String entityName)
+            final String containerCode, final String entityCode, final String dataSetTypeCode, final String dataSetCode,
+            final String dataSetName, final String fileName)
     {
-        ExportExecutor.getFolderName(prefix, spaceCode, projectCode, containerCode, entityCode, entityName);
+        ExportExecutor.getFolderName(prefix, spaceCode, projectCode, containerCode, entityCode, dataSetTypeCode, dataSetCode, dataSetName, fileName);
     }
 
     @Test()