diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandTestValid.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandTestValid.java index c557d1f12a8322bafddc6ae7ea3f51587ebb02e2..dca6e2944319202d77075d36eb559da31c6c7e81 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandTestValid.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandTestValid.java @@ -314,6 +314,19 @@ class CommandTestValid extends AbstractDssCommand<CommandTestValid.CommandTestVa { } + @Override + public InputStream getFileFromSessionWorkspace(String filePath) + throws IOExceptionUnchecked + { + return null; + } + + @Override + public void getFileFromSessionWorkspace(String filePath, File localFile) + throws IOExceptionUnchecked + { + } + @Override public boolean deleteSessionWorkspaceFile(String path) { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDssComponent.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDssComponent.java index cd6d91526ff13326364cb29ef8de26fd74550acd..6ea58ccdaebec45b5a3332c650d60ce1fbc93911 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDssComponent.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDssComponent.java @@ -89,8 +89,7 @@ public interface IDssComponent * Uploads a file to the session workspace. * * @param filePath The path (directory and name) of the file to upload. - * @param inputStream The data of the file to upload. - * + * @param inputStream The content of the file to upload. * @throws IOExceptionUnchecked If the file transfer fails. */ public void putFileToSessionWorkspace(String filePath, InputStream inputStream) @@ -101,19 +100,37 @@ public interface IDssComponent * * @param directory The directory in the session workspace where the file should be uploaded. * @param file The file to upload. - * - * @throws IOExceptionUnchecked If the file transfer fails. + * @throws IOExceptionUnchecked If the file cannot be written. */ public void putFileToSessionWorkspace(String directory, File file) throws IOExceptionUnchecked; + /** + * Downloads a file from the session workspace. + * + * @param filePath The path (directory and name) of the file to download. + * @return outputStream The content of the file to download. + * @throws IOExceptionUnchecked If the file does not exist, is a directory or cannot be opened. + */ + public InputStream getFileFromSessionWorkspace(String filePath) throws IOExceptionUnchecked; + + /** + * Downloads a file from the session workspace. + * + * @param filePath The path (directory and name) of the file to download. + * @param localFile The local file to write the file from the session workspace to. + * @throws IOExceptionUnchecked If the file does not exist. + */ + public void getFileFromSessionWorkspace(String filePath, File localFile) + throws IOExceptionUnchecked; + /** * Delete a file or directory in the session workspace. * * @return <code>true</code> if the <var>path</var> doesn't exist anymore. */ public boolean deleteSessionWorkspaceFile(String path); - + /** * Validate a data set. * diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponent.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponent.java index 196155ad996b066856883abc6ed380a77e662818..48b34ecc22f1cd356135ed873567529ee5fa0e45 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponent.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponent.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; @@ -30,6 +31,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.io.IOUtils; import org.python.core.Py; import org.python.core.PyException; import org.springframework.remoting.RemoteAccessException; @@ -59,6 +61,8 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.validation.ValidationE import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.validation.ValidationScriptRunner; import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationService; +import de.schlichtherle.io.FileOutputStream; + /** * Implementation of the IDssComponent interface. It is a facade for interacting with openBIS and * multiple DSS servers. @@ -236,6 +240,19 @@ public class DssComponent implements IDssComponent state.putFileToSessionWorkspace(directory, file); } + @Override + public InputStream getFileFromSessionWorkspace(String filePath) throws IOExceptionUnchecked + { + return state.getFileFromSessionWorkspace(filePath); + } + + @Override + public void getFileFromSessionWorkspace(String filePath, File localFile) + throws IOExceptionUnchecked + { + state.getFileFromSessionWorkspace(filePath, localFile); + } + @Override public boolean deleteSessionWorkspaceFile(String path) { @@ -307,6 +324,19 @@ abstract class AbstractDssComponentState implements IDssComponent throw new IllegalStateException("Please log in"); } + @Override + public InputStream getFileFromSessionWorkspace(String filePath) throws IOExceptionUnchecked + { + throw new IllegalStateException("Please log in"); + } + + @Override + public void getFileFromSessionWorkspace(String filePath, File localFile) + throws IOExceptionUnchecked + { + throw new IllegalStateException("Please log in"); + } + @Override public boolean deleteSessionWorkspaceFile(String path) { @@ -477,25 +507,47 @@ class AuthenticatedState extends AbstractDssComponentState { final IDssServiceRpcGeneric dssService = getServiceForPutDataStore(); final String filePath = directory + "/" + file.getName(); - InputStream inputStream = null; + InputStream istream = null; try { - inputStream = new FileInputStream(file); - dssService.putFileToSessionWorkspace(sessionToken, filePath, inputStream); + istream = new FileInputStream(file); + dssService.putFileToSessionWorkspace(sessionToken, filePath, istream); } catch (IOException ex) { throw CheckedExceptionTunnel.wrapIfNecessary(ex); } finally { - if (inputStream != null) - { - try - { - inputStream.close(); - } catch (IOException ex) - { - } - } + IOUtils.closeQuietly(istream); + } + } + + @Override + public InputStream getFileFromSessionWorkspace(String filePath) throws IOExceptionUnchecked + { + final IDssServiceRpcGeneric dssService = getServiceForPutDataStore(); + return dssService.getFileFromSessionWorkspace(sessionToken, filePath); + } + + @Override + public void getFileFromSessionWorkspace(String filePath, File localFile) + throws IOExceptionUnchecked + { + final IDssServiceRpcGeneric dssService = getServiceForPutDataStore(); + final InputStream istream = dssService.getFileFromSessionWorkspace(sessionToken, filePath); + OutputStream ostream = null; + try + { + ostream = new FileOutputStream(localFile); + IOUtils.copyLarge(istream, ostream); + ostream.close(); + } catch (IOException ex) + { + localFile.delete(); + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } finally + { + IOUtils.closeQuietly(istream); + IOUtils.closeQuietly(ostream); } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java index 0f67590039eff3c81ec0bcc39117ccd3b065a74f..2a2cea1cc1c703cae6e6dcd1e785804e39ca3161 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java @@ -17,6 +17,8 @@ package ch.systemsx.cisd.openbis.dss.generic.server.api.v1; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -226,6 +228,28 @@ public class DssServiceRpcGeneric extends AbstractDssServiceRpc<IDssServiceRpcGe } } + @Override + public InputStream getFileFromSessionWorkspace(String sessionToken, String filePath) + throws IOExceptionUnchecked + { + getOpenBISService().checkSession(sessionToken); + if (filePath.contains("../")) + { + throw new IOExceptionUnchecked("filePath must not contain '../'"); + } + final File workspaceDir = + new SessionWorkspaceProvider(sessionWorkspaceRootDirectory, sessionToken) + .getSessionWorkspace(); + final File file = new File(workspaceDir, filePath); + try + { + return new FileInputStream(file); + } catch (FileNotFoundException ex) + { + throw new IOExceptionUnchecked(ex); + } + } + @Override public boolean deleteSessionWorkspaceFile(String sessionToken, String path) { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGenericLogger.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGenericLogger.java index 8b4341b21dc390874085b50d78bb26cab3ec0887..8ae2e89f244a5351375af7f23b7d925631b3ee71 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGenericLogger.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGenericLogger.java @@ -117,6 +117,15 @@ public class DssServiceRpcGenericLogger extends AbstractServerLogger implements logTracking(sessionToken, "put_file_to_session_workspace", "FILE_PATH(%s)", filePath); } + @Override + @DataSetAccessGuard + public InputStream getFileFromSessionWorkspace(String sessionToken, String filePath) + throws IOExceptionUnchecked + { + logAccess(sessionToken, "get_file_from_session_workspace", "FILE_PATH(%s)", filePath); + return null; + } + @Override public boolean deleteSessionWorkspaceFile(String sessionToken, String path) { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/IDssServiceRpcGeneric.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/IDssServiceRpcGeneric.java index 122fd080dcff501cc4565d61a433704209fdc815..8460b00c32ebebc41dbe3f74b3727b25ca0335c8 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/IDssServiceRpcGeneric.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/IDssServiceRpcGeneric.java @@ -46,7 +46,8 @@ public interface IDssServiceRpcGeneric extends IRpcService @DataSetAccessGuard public FileInfoDssDTO[] listFilesForDataSet( String sessionToken, - @AuthorizationGuard(guardClass = DataSetFileDTOPredicate.class) DataSetFileDTO fileOrFolder) + @AuthorizationGuard(guardClass = DataSetFileDTOPredicate.class) + DataSetFileDTO fileOrFolder) throws IOExceptionUnchecked, IllegalArgumentException; /** @@ -62,7 +63,8 @@ public interface IDssServiceRpcGeneric extends IRpcService @Deprecated public InputStream getFileForDataSet( String sessionToken, - @AuthorizationGuard(guardClass = DataSetFileDTOPredicate.class) DataSetFileDTO fileOrFolder) + @AuthorizationGuard(guardClass = DataSetFileDTOPredicate.class) + DataSetFileDTO fileOrFolder) throws IOExceptionUnchecked, IllegalArgumentException; /** @@ -78,9 +80,10 @@ public interface IDssServiceRpcGeneric extends IRpcService @DataSetAccessGuard public String getDownloadUrlForFileForDataSet( String sessionToken, - @AuthorizationGuard(guardClass = DataSetFileDTOPredicate.class) DataSetFileDTO fileOrFolder) - throws IOExceptionUnchecked, IllegalArgumentException; - + @AuthorizationGuard(guardClass = DataSetFileDTOPredicate.class) + DataSetFileDTO fileOrFolder) + throws IOExceptionUnchecked, IllegalArgumentException; + /** * Get an array of FileInfoDss objects that describe the file-system structure of the data set. * @@ -93,7 +96,8 @@ public interface IDssServiceRpcGeneric extends IRpcService */ @DataSetAccessGuard public FileInfoDssDTO[] listFilesForDataSet(String sessionToken, - @AuthorizationGuard(guardClass = DataSetCodeStringPredicate.class) String dataSetCode, + @AuthorizationGuard(guardClass = DataSetCodeStringPredicate.class) + String dataSetCode, String path, boolean isRecursive) throws IOExceptionUnchecked, IllegalArgumentException; /** @@ -109,7 +113,8 @@ public interface IDssServiceRpcGeneric extends IRpcService @DataSetAccessGuard @Deprecated public InputStream getFileForDataSet(String sessionToken, - @AuthorizationGuard(guardClass = DataSetCodeStringPredicate.class) String dataSetCode, + @AuthorizationGuard(guardClass = DataSetCodeStringPredicate.class) + String dataSetCode, String path) throws IOExceptionUnchecked, IllegalArgumentException; /** @@ -125,9 +130,10 @@ public interface IDssServiceRpcGeneric extends IRpcService */ @DataSetAccessGuard public String getDownloadUrlForFileForDataSet(String sessionToken, - @AuthorizationGuard(guardClass = DataSetCodeStringPredicate.class) String dataSetCode, + @AuthorizationGuard(guardClass = DataSetCodeStringPredicate.class) + String dataSetCode, String path) throws IOExceptionUnchecked, IllegalArgumentException; - + /** * Upload a new data set to the DSS. * @@ -140,7 +146,8 @@ public interface IDssServiceRpcGeneric extends IRpcService */ @DataSetAccessGuard public String putDataSet(String sessionToken, - @AuthorizationGuard(guardClass = NewDataSetPredicate.class) NewDataSetDTO newDataset, + @AuthorizationGuard(guardClass = NewDataSetPredicate.class) + NewDataSetDTO newDataset, InputStream inputStream) throws IOExceptionUnchecked, IllegalArgumentException; /** @@ -149,20 +156,29 @@ public interface IDssServiceRpcGeneric extends IRpcService * @param sessionToken The session token. * @param filePath The file path (including the sub-directory) to upload the file to. * @param inputStream An input stream on the file to upload. - * @throws IOExceptionUnchecked Thrown if an IOException. + * @throws IOExceptionUnchecked Thrown if because <var>filePath</var> does not exist. */ - @DataSetAccessGuard public void putFileToSessionWorkspace(String sessionToken, String filePath, InputStream inputStream) throws IOExceptionUnchecked; + /** + * Download a new file from the user's session workspace. + * + * @param sessionToken The session token. + * @param filePath The file path (including the sub-directory) to upload the file to. + * @return The output stream containing the file content. + * @throws IOExceptionUnchecked Thrown if an IOException occurs. + */ + public InputStream getFileFromSessionWorkspace(String sessionToken, String filePath) + throws IOExceptionUnchecked; + /** * Delete a file or directory in the session workspace. * * @return <code>true</code> if the <var>path</var> doesn't exist anymore. */ - @DataSetAccessGuard public boolean deleteSessionWorkspaceFile(String sessionToken, String path); - + /** * Get a path to the data set. This can be used by clients that run on the same machine as the * DSS for more efficient access to a data set. @@ -182,8 +198,10 @@ public interface IDssServiceRpcGeneric extends IRpcService */ @DataSetAccessGuard(releaseDataSetLocks = false) public String getPathToDataSet(String sessionToken, - @AuthorizationGuard(guardClass = DataSetCodeStringPredicate.class) String dataSetCode, - String overrideStoreRootPathOrNull) throws IOExceptionUnchecked, IllegalArgumentException; + @AuthorizationGuard(guardClass = DataSetCodeStringPredicate.class) + String dataSetCode, + String overrideStoreRootPathOrNull) throws IOExceptionUnchecked, + IllegalArgumentException; /** * Get the validation script for the specified data set type. diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTest.java index 6d1e0449259b5a4755ec916918376a2bec7e87f0..32fb85b442ab275df33d1db0eec04d04bc6ea428 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTest.java @@ -670,6 +670,13 @@ public class DssComponentTest extends AbstractFileSystemTestCase return false; } + @Override + public InputStream getFileFromSessionWorkspace(String sessionToken, String filePath) + throws IOExceptionUnchecked + { + return null; + } + } private class MockDssServiceRpcV1_1 extends MockDssServiceRpcV1_0