diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApi.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApi.java index 87d81735ed0e5a5312be38c4426e2d3c84fb77b1..b7fe35041edbcab9f98a982d470fb1d6c22fbc9d 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApi.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApi.java @@ -29,6 +29,7 @@ import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.TreeMap; +import java.util.TreeSet; import java.util.stream.Collectors; import org.apache.commons.collections4.iterators.IteratorChain; @@ -350,7 +351,7 @@ public class DataStoreServerApi extends AbstractDssServiceRpc<IDataStoreServerAp Set<String> ids = filesByDataSet.get(dataSetCode); if (ids == null) { - ids = new HashSet<>(); + ids = new TreeSet<>(); filesByDataSet.put(dataSetCode, ids); } String filePath = filePermId.getFilePath(); diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/FileTransferServerServlet.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/FileTransferServerServlet.java index 21bf52d3c696206e82413f7768e68d575a538994..e3b62b6ff710942cee817f5b6db766d664bb6ae0 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/FileTransferServerServlet.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/FileTransferServerServlet.java @@ -85,14 +85,15 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.Ds /** * Servlet which provides download service of data set files using the file-transfer protocol. + * * @author Franz-Josef Elmer */ public class FileTransferServerServlet extends HttpServlet { private static final long serialVersionUID = 1L; - + public static final String SERVLET_NAME = "file-transfer"; - + private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, FileTransferServerServlet.class); @@ -268,7 +269,7 @@ public class FileTransferServerServlet extends HttpServlet private DownloadSessionId getDownloadSessionId(Map<String, String[]> parameterMap) throws ServletException { DownloadSessionId downloadSessionId = new DownloadSessionId(); - ClassUtils.setFieldValue(downloadSessionId, "id", getParameters(parameterMap, + ClassUtils.setFieldValue(downloadSessionId, "id", getParameters(parameterMap, FastDownloadParameter.DOWNLOAD_SESSION_ID_PARAMETER).get(0)); return downloadSessionId; } @@ -317,20 +318,24 @@ public class FileTransferServerServlet extends HttpServlet private ConcurrencyProvider(Properties properties) { maximumNumberOfAllowedStreams = PropertyUtils.getInt(properties, "api.v3.fast-download.maximum-number-of-allowed-streams", 10); - operationLog.info("max number of allowed streams: "+ maximumNumberOfAllowedStreams); + operationLog.info("max number of allowed streams: " + maximumNumberOfAllowedStreams); } @Override public int getAllowedNumberOfStreams(IUserSessionId userSessionId, Integer wishedNumberOfStreams, List<DownloadState> downloadStates) throws DownloadException { - int allowedNumberOfStreams = maximumNumberOfAllowedStreams; - for (DownloadState downloadState : downloadStates) + int currentNumberOfStreams = downloadStates.stream().collect(Collectors.summingInt(DownloadState::getCurrentNumberOfStreams)); + int freeNumberOfStreams = maximumNumberOfAllowedStreams - currentNumberOfStreams; + int allowedNumberOfStreams = freeNumberOfStreams / 2; + if (wishedNumberOfStreams != null && wishedNumberOfStreams < allowedNumberOfStreams) { - allowedNumberOfStreams -= downloadState.getCurrentNumberOfStreams(); + allowedNumberOfStreams = wishedNumberOfStreams; } - System.err.println("allowed number of streams:"+allowedNumberOfStreams+" "+downloadStates.size()); - return Math.min(wishedNumberOfStreams == null ? 1 : wishedNumberOfStreams, allowedNumberOfStreams); + operationLog.info("current number of streams: " + currentNumberOfStreams + ", wished number of streams: " + + (wishedNumberOfStreams == null ? "unspecified" : wishedNumberOfStreams) + + ", allowed number of streams: " + allowedNumberOfStreams); + return allowedNumberOfStreams; } } diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/AbstractFileTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/AbstractFileTest.java index 71466ad2ee7e78a15d3cb73edbeb3384a9a91e0a..0b2edd497ff56147115ae1b414eb35f7aaf44b27 100644 --- a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/AbstractFileTest.java +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/AbstractFileTest.java @@ -115,7 +115,7 @@ public class AbstractFileTest extends SystemTestCase protected String createRandomContent(String path) { StringBuilder builder = new StringBuilder().append("file content of ").append(path).append("\n"); - for (int i = 0; i < 10000; i++) + for (int i = 0; i < 30000; i++) { builder.append(UUID.nameUUIDFromBytes((path+ " "+i).getBytes()).toString()).append("\n"); } diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/DownloadFileTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/DownloadFileTest.java index 63a8505ed1471a8c8cebcee881e8df1bbd966dde..544d3daaa7e4af0a870c0df6bab18d3d689dfec3 100644 --- a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/DownloadFileTest.java +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/DownloadFileTest.java @@ -1,25 +1,51 @@ package ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; +import java.io.File; import java.io.InputStream; +import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; import org.apache.commons.io.IOUtils; import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import ch.ethz.sis.filetransfer.DownloadException; +import ch.ethz.sis.filetransfer.DownloadStatus; +import ch.ethz.sis.filetransfer.IDownloadItemId; +import ch.ethz.sis.filetransfer.IDownloadListener; +import ch.ethz.sis.filetransfer.ILogger; +import ch.ethz.sis.filetransfer.LogLevel; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetFetchOptions; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId; 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.fastdownload.FastDownloadSession; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.fastdownload.FastDownloadSessionOptions; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.DataSetFilePermId; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.IDataSetFileId; +import ch.ethz.sis.openbis.generic.dssapi.v3.fastdownload.FastDownloadResult; +import ch.ethz.sis.openbis.generic.dssapi.v3.fastdownload.FastDownloader; +import ch.systemsx.cisd.common.collection.SimpleComparator; +import ch.systemsx.cisd.common.exceptions.ExceptionUtils; +import ch.systemsx.cisd.common.filesystem.FileUtilities; public class DownloadFileTest extends AbstractFileTest { + private File target; + @Override @BeforeClass protected void beforeClass() throws Exception @@ -28,6 +54,152 @@ public class DownloadFileTest extends AbstractFileTest registerDataSet(); } + @BeforeMethod + public void setUp() + { + target = new File(workingDirectory, "file-downloads"); + FileUtilities.deleteRecursively(target); + } + + @Test + public void testFastDownloadOfACompleteDataSet() + { + // Given + String sessionToken = as.login(TEST_USER, PASSWORD); + DataSetFilePermId root = new DataSetFilePermId(new DataSetPermId(dataSetCode), ""); + List<DataSetFilePermId> fileIds = Arrays.asList(root); + FastDownloadSessionOptions options = new FastDownloadSessionOptions().withWishedNumberOfStreams(1); + + // When + FastDownloadSession downloadSession = dss.createFastDownloadSession(sessionToken, fileIds, options); + FastDownloadResult downloadResult = new FastDownloader(downloadSession).downloadTo(target); + + // Then + assertEquals(DownloadStatus.FINISHED, downloadResult.getStatus()); + assertDownloads(sessionToken, downloadResult.getPathsById(), fileIds); + } + + @Test + public void testFastDownloadOfAFileWithLogger() + { + // Given + String sessionToken = as.login(TEST_USER, PASSWORD); + DataSetFilePermId fileId = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("subdir3/file6.txt")); + List<DataSetFilePermId> fileIds = Arrays.asList(fileId); + FastDownloadSessionOptions options = new FastDownloadSessionOptions().withWishedNumberOfStreams(1); + ILogger logger = new RecordingLogger(); + + // When + FastDownloadSession downloadSession = dss.createFastDownloadSession(sessionToken, fileIds, options); + FastDownloadResult downloadResult = new FastDownloader(downloadSession).withLogger(logger) + .downloadTo(target); + + // Then + assertEquals(DownloadStatus.FINISHED, downloadResult.getStatus()); + assertDownloads(sessionToken, downloadResult.getPathsById(), fileIds); + assertEquals("log: class ch.ethz.sis.filetransfer.DownloadClientDownload INFO Download state changed to: STARTED\n" + + "log: class ch.ethz.sis.filetransfer.DownloadClientDownload INFO Download state changed to: FINISHED\n", + logger.toString()); + } + + @Test + public void testFastDownloadAFileWithListener() + { + // Given + String sessionToken = as.login(TEST_USER, PASSWORD); + DataSetFilePermId file = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("file1.txt")); + List<DataSetFilePermId> fileIds = Arrays.asList(file); + FastDownloadSessionOptions options = new FastDownloadSessionOptions().withWishedNumberOfStreams(1); + IDownloadListener listener = new RecordingListener(); + + // When + FastDownloadSession downloadSession = dss.createFastDownloadSession(sessionToken, fileIds, options); + FastDownloadResult downloadResult = new FastDownloader(downloadSession).withListener(listener).downloadTo(target); + + // Then + assertEquals(DownloadStatus.FINISHED, downloadResult.getStatus()); + assertDownloads(sessionToken, downloadResult.getPathsById(), fileIds); + String id1 = "DownloadItemId[id=" + dataSetCode + "/" + file.getFilePath() + "]"; + String path1 = "targets/unit-test-wd/SystemTests/file-downloads/" + dataSetCode + "/" + file.getFilePath(); + assertEquals("onDownloadStarted:\n" + + "onItemStarted: " + id1 + "\n" + + "onChunkDownloaded: 0\n" + + "onChunkDownloaded: 1\n" + + "onItemFinished: " + id1 + " " + path1 + "\n" + + "onDownloadFinished: [" + id1 + "=" + path1 + "]\n", listener.toString()); + } + + @Test + public void testFastDownloadAFolderWithListener() + { + // Given + String sessionToken = as.login(TEST_USER, PASSWORD); + DataSetFilePermId folder = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("subdir1")); + List<DataSetFilePermId> fileIds = Arrays.asList(folder); + FastDownloadSessionOptions options = new FastDownloadSessionOptions().withWishedNumberOfStreams(1); + IDownloadListener listener = new RecordingListener(); + + // When + FastDownloadSession downloadSession = dss.createFastDownloadSession(sessionToken, fileIds, options); + FastDownloadResult downloadResult = new FastDownloader(downloadSession).withListener(listener).downloadTo(target); + + // Then + assertEquals(DownloadStatus.FINISHED, downloadResult.getStatus()); + assertDownloads(sessionToken, downloadResult.getPathsById(), fileIds); + String id2 = "DownloadItemId[id=" + dataSetCode + "/" + folder.getFilePath() + "]"; + String path2 = "targets/unit-test-wd/SystemTests/file-downloads/" + dataSetCode + "/" + folder.getFilePath(); + assertEquals("onDownloadStarted:\n" + + "onItemStarted: " + id2 + "\n" + + "onChunkDownloaded: 0\n" + + "onChunkDownloaded: 1\n" + + "onChunkDownloaded: 2\n" + + "onChunkDownloaded: 3\n" + + "onChunkDownloaded: 4\n" + + "onChunkDownloaded: 5\n" + + "onItemFinished: " + id2 + " " + path2 + "\n" + + "onDownloadFinished: [" + id2 + "=" + path2 + "]\n", listener.toString()); + } + + @Test + public void testFastDownloadUnauthorized() + { + // Given + String sessionToken = as.login(TEST_SPACE_USER, PASSWORD); + DataSetFilePermId folder = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("subdir1")); + List<DataSetFilePermId> fileIds = Arrays.asList(folder); + FastDownloadSessionOptions options = new FastDownloadSessionOptions().withWishedNumberOfStreams(1); + + // When + FastDownloadSession downloadSession = dss.createFastDownloadSession(sessionToken, fileIds, options); + + // Then + assertEquals("[]", downloadSession.getFiles().toString()); + } + + @Test + public void testFastDownloadUnauthorizedByCheating() + { + // Given + String sessionToken = as.login(TEST_SPACE_USER, PASSWORD); + DataSetFilePermId folder = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("subdir1")); + List<DataSetFilePermId> fileIds = Arrays.asList(folder); + FastDownloadSessionOptions options = new FastDownloadSessionOptions().withWishedNumberOfStreams(1); + FastDownloadSession downloadSession = dss.createFastDownloadSession(sessionToken, fileIds, options); + assertEquals(0, downloadSession.getFiles().size()); + downloadSession.getFiles().add(folder); + + try + { + // When + new FastDownloader(downloadSession).downloadTo(target); + fail("DownloadException expected"); + } catch (DownloadException e) + { + // Then + assertEquals("java.lang.IllegalArgumentException: Item ids cannot be null or empty", ExceptionUtils.getEndOfChain(e).getMessage()); + } + } + @Test public void testDownloadUnauthorized() { @@ -222,4 +394,160 @@ public class DownloadFileTest extends AbstractFileTest { return "original/" + dataSetCode + "/"; } + + private void assertDownloads(String sessionToken, Map<IDataSetFileId, Path> pathsById, List<DataSetFilePermId> fileIds) + { + System.out.println("PATHS BY ID:" + pathsById); + List<IDataSetId> dataSetIds = new ArrayList<>(fileIds.stream().map(DataSetFilePermId::getDataSetId).collect(Collectors.toSet())); + DataSetFetchOptions fetchOptions = new DataSetFetchOptions(); + fetchOptions.withPhysicalData(); + Map<IDataSetId, DataSet> dataSets = as.getDataSets(sessionToken, dataSetIds, fetchOptions); + for (DataSetFilePermId fileId : fileIds) + { + String location = dataSets.get(fileId.getDataSetId()).getPhysicalData().getLocation(); + File expectedFile = new File(store, "1/" + location + "/" + fileId.getFilePath()); + Path path = pathsById.get(fileId); + assertNotNull("Path for file " + fileId, path); + File actualFile = path.toFile(); + assertSameContent(expectedFile, actualFile); + } + assertEquals(fileIds.size(), pathsById.size()); + } + + private void assertSameContent(File expectedFile, File actualFile) + { + assertEquals(expectedFile.getName(), actualFile.getName()); + assertEquals(actualFile + " exists", expectedFile.exists(), actualFile.exists()); + assertEquals(actualFile + " is directory", expectedFile.isDirectory(), actualFile.isDirectory()); + if (actualFile.isDirectory()) + { + List<File> expectedChildren = Arrays.asList(expectedFile.listFiles()); + Collections.sort(expectedChildren); + List<String> expectedChildrenNames = expectedChildren.stream().map(File::getName).collect(Collectors.toList()); + List<File> actualChildren = Arrays.asList(actualFile.listFiles()); + Collections.sort(actualChildren); + List<String> actualChildrenNames = actualChildren.stream().map(File::getName).collect(Collectors.toList()); + assertEquals(expectedChildrenNames, actualChildrenNames); + for (int i = 0, n = expectedChildren.size(); i < n; i++) + { + assertSameContent(expectedChildren.get(i), actualChildren.get(i)); + } + } else + { + assertEquals(FileUtilities.loadToString(expectedFile), FileUtilities.loadToString(actualFile)); + } + } + + private static final class RecordingLogger implements ILogger + { + private List<Event> events = new ArrayList<>(); + + @Override + public boolean isEnabled(LogLevel level) + { + return LogLevel.INFO.compareTo(level) <= 0; + } + + @Override + public void log(Class<?> clazz, LogLevel level, String message) + { + events.add(new Event("log", clazz, level, message)); + } + + @Override + public void log(Class<?> clazz, LogLevel level, String message, Throwable throwable) + { + events.add(new Event("logWithThrowable", clazz, level, message, throwable)); + } + + @Override + public String toString() + { + return render(events); + } + } + + private static final class RecordingListener implements IDownloadListener + { + private List<Event> events = new ArrayList<>(); + + @Override + public void onDownloadStarted() + { + events.add(new Event("onDownloadStarted")); + } + + @Override + public void onDownloadFinished(Map<IDownloadItemId, Path> itemPaths) + { + List<Entry<IDownloadItemId, Path>> list = new ArrayList<>(itemPaths.entrySet()); + Collections.sort(list, new SimpleComparator<Entry<IDownloadItemId, Path>, String>() + { + @Override + public String evaluate(Entry<IDownloadItemId, Path> item) + { + return item.getKey().getId(); + } + }); + events.add(new Event("onDownloadFinished", list)); + } + + @Override + public void onDownloadFailed(Collection<Exception> e) + { + events.add(new Event("onDownloadFailed", e)); + } + + @Override + public void onItemStarted(IDownloadItemId itemId) + { + events.add(new Event("onItemStarted", itemId)); + } + + @Override + public void onItemFinished(IDownloadItemId itemId, Path itemPath) + { + events.add(new Event("onItemFinished", itemId, itemPath)); + } + + @Override + public void onChunkDownloaded(int sequenceNumber) + { + events.add(new Event("onChunkDownloaded", sequenceNumber)); + } + + @Override + public String toString() + { + return render(events); + } + } + + private static final class Event + { + private String type; + + private Object[] parameters; + + Event(String type, Object... parameters) + { + this.type = type; + this.parameters = parameters; + } + } + + private static final String render(List<Event> events) + { + StringBuilder builder = new StringBuilder(); + for (Event event : events) + { + builder.append(event.type).append(":"); + for (Object parameter : event.parameters) + { + builder.append(" ").append(parameter); + } + builder.append("\n"); + } + return builder.toString(); + } } \ No newline at end of file diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/fastdownload/FastDownloader.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/fastdownload/FastDownloader.java index 838cfcb33390e8c19f90ec9dd58baccdb1cf9ec4..52ad17d22d7fa9e766a9c672440c17a3a5b814e3 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/fastdownload/FastDownloader.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/fastdownload/FastDownloader.java @@ -30,6 +30,7 @@ import ch.ethz.sis.filetransfer.DownloadClientConfig; import ch.ethz.sis.filetransfer.DownloadClientDownload; import ch.ethz.sis.filetransfer.DownloadException; import ch.ethz.sis.filetransfer.DownloadItemId; +import ch.ethz.sis.filetransfer.DownloadItemNotFoundException; import ch.ethz.sis.filetransfer.DownloadPreferences; import ch.ethz.sis.filetransfer.DownloadSessionId; import ch.ethz.sis.filetransfer.FileSystemDownloadStore; @@ -37,8 +38,6 @@ import ch.ethz.sis.filetransfer.IDownloadItemId; import ch.ethz.sis.filetransfer.IDownloadItemIdDeserializer; import ch.ethz.sis.filetransfer.IDownloadListener; import ch.ethz.sis.filetransfer.IDownloadServer; -import ch.ethz.sis.filetransfer.IDownloadStore; -import ch.ethz.sis.filetransfer.IDownloadStoreFactory; import ch.ethz.sis.filetransfer.ILogger; import ch.ethz.sis.filetransfer.IRetryProvider; import ch.ethz.sis.filetransfer.IRetryProviderFactory; @@ -77,8 +76,6 @@ public class FastDownloader private List<IDownloadListener> listeners = new ArrayList<>(); - private IDownloadStoreFactory storeFactory; - private IRetryProviderFactory retryProviderFactory; private UserSessionId userSessionId; @@ -157,18 +154,6 @@ public class FastDownloader return this; } - /** - * Sets the factory for an {@link IDownloadStore}. By default the downloaded files are stored in the root folder (parameter of method - * {{@link #downloadTo(File)}) as follows: <data set code>/<file path in the data set> - * - * @return this instance - */ - public FastDownloader withDownloadStoreFactory(IDownloadStoreFactory storeFactory) - { - this.storeFactory = storeFactory; - return this; - } - /** * Sets the factory for an {@link IRetryProvider}. The default is {@link DefaultRetryProvider} with maximumNumberOfRetries = 3, * waitingTimeBetweenRetries = 1 sec, waitingTimeBetweenRetriesIncreasingFactor = 2. @@ -207,18 +192,31 @@ public class FastDownloader DownloadClientConfig config = new DownloadClientConfig(); config.setServer(getDownloadServer()); config.setLogger(actualLogger); - config.setStore(storeFactory != null ? storeFactory.createStore(actualLogger, root) - : new FileSystemDownloadStore(actualLogger, root) + config.setStore(new FileSystemDownloadStore(actualLogger, root) + { + @Override + protected Path getItemDirectory(IUserSessionId userSessionId, DownloadSessionId downloadSessionId, + IDownloadItemId itemId) throws DownloadException + { + String[] splitted = itemId.getId().split("/", 2); + String dataSetCode = splitted[0]; + return root.resolve(dataSetCode); + } + + @Override + public Path getItemPath(IUserSessionId userSessionId, DownloadSessionId downloadSessionId, IDownloadItemId itemId) + throws DownloadException + { + Path itemDirectory = getItemDirectory(userSessionId, downloadSessionId, itemId); + String[] splitted = itemId.getId().split("/", 2); + Path itemPath = itemDirectory.resolve(splitted[1]); + if (itemPath.toFile().exists()) { - @Override - protected Path getItemDirectory(IUserSessionId userSessionId, DownloadSessionId downloadSessionId, - IDownloadItemId itemId) throws DownloadException - { - String[] splitted = itemId.getId().split("/", 2); - String dataSetCode = splitted[0]; - return root.resolve(dataSetCode); - } - }); + return itemPath; + } + throw new DownloadItemNotFoundException("Store does not contain any files for download item id: " + itemId); + } + }); config.setDeserializerProvider(new DefaultDeserializerProvider(actualLogger, new IDownloadItemIdDeserializer() {