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()