diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/SessionWorkspaceFileUploadServlet.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/SessionWorkspaceFileUploadServlet.java index 36f175546bfbec7cf65740711f837aa2c0f1b4fc..87ded2540f8fbf2c8e930dd09546b7e2373152d3 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/SessionWorkspaceFileUploadServlet.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/SessionWorkspaceFileUploadServlet.java @@ -63,7 +63,10 @@ public class SessionWorkspaceFileUploadServlet extends HttpServlet private static final String STATUS_PARAM = "status"; - public static final String UPLOAD_ID_PARAM = "uploadID"; + /** If present, the file being uploaded is just an empty folder, not a file upload. */ + private static final String IS_EMPTY_FOLDER = "emptyFolder"; + + private static final String UPLOAD_ID_PARAM = "uploadID"; private IDssServiceRpcGeneric service; diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/OpenBisFacade.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/OpenBisFacade.java deleted file mode 100644 index b49e16e60483b5ca8fc32af3d5d054887e777b35..0000000000000000000000000000000000000000 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/OpenBisFacade.java +++ /dev/null @@ -1,123 +0,0 @@ -package ch.ethz.sis.openbis.generic.server.asapi.v3; - -import java.io.File; -import java.net.URI; -import java.net.URLEncoder; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.time.Duration; -import java.util.Map; - -import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; -import ch.systemsx.cisd.common.spring.HttpInvokerUtils; -import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException; - -public class OpenBisFacade -{ - - public static final int TIMEOUT_IN_MILLIS = 30000; - - public static String uploadFileWorkspaceDss(final File[] filesOrFolders) - { -// final ServiceFinder serviceFinder = new ServiceFinder("openbis", "session_workspace_file_upload"); -// serviceFinder.computeServerUrl() - final IApplicationServerApi v3 = HttpInvokerUtils.createServiceStub(IApplicationServerApi.class, - "http://localhost:8888/openbis/openbis" + IApplicationServerApi.SERVICE_URL, 10000); - - final String sessionToken = v3.login("admin", "cahngeit"); - System.out.println("Session token: " + sessionToken); - - try - { - final File file = filesOrFolders[0]; - - if (!file.isFile()) - { - throw new UserFailureException("File must me a file for now."); - } - - final String fileName = file.getName(); - - final byte[] respose = request("POST", new URI("http://localhost:8889/datastore_server/session_workspace_file_upload"), - Map.of( - "sessionID", sessionToken, - "filename", fileName, - "id", "0", - "startByte", "0", - "endByte", String.valueOf(file.length()), - "size", String.valueOf(file.length()) - ), Files.readAllBytes(file.toPath())); - System.out.println(new String(respose)); - } catch (Exception e) - { - throw new RuntimeException(e); - } finally - { - v3.logout(sessionToken); - } - - // TODO: implement. - return null; - } - - public static DataSetPermId createUploadedDataSet(final String sessionToken, final UploadedDataSetCreation creation) - { - // TODO: implement. - return null; - } - - @SuppressWarnings({ "OptionalGetWithoutIsPresent", "unchecked" }) - private static byte[] request(final String httpMethod, final URI serverUri, - final Map<String, String> parameters, final byte [] body) throws Exception { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_1_1) - .followRedirects(HttpClient.Redirect.NORMAL) - .connectTimeout(Duration.ofMillis(TIMEOUT_IN_MILLIS)) - .build(); - - final String query = parameters.entrySet().stream() - .map(entry -> urlEncode(entry.getKey()) + "=" + urlEncode(entry.getValue())) - .reduce((s1, s2) -> s1 + "&" + s2).get(); - - final URI uri = new URI(serverUri.getScheme(), null, serverUri.getHost(), serverUri.getPort(), - serverUri.getPath(), query, null); - - final HttpRequest.Builder builder = HttpRequest.newBuilder() - .uri(uri) - .version(HttpClient.Version.HTTP_1_1) - .timeout(Duration.ofMillis(TIMEOUT_IN_MILLIS)) - .method(httpMethod, HttpRequest.BodyPublishers.ofByteArray(body)); - - final HttpRequest request = builder.build(); - - final HttpResponse<byte[]> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofByteArray()); - - final int statusCode = httpResponse.statusCode(); - if (statusCode >= 200 && statusCode < 300) { - return httpResponse.body(); - } else if (statusCode >= 400 && statusCode < 500) { - throw new UserFailureException("User failure. Received status code: " + statusCode + ". Body: " + - new String(httpResponse.body())); - } else if (statusCode >= 500 && statusCode < 600) { - throw new RuntimeException("Server failure. Received status code: " + statusCode); - } else { - throw new RuntimeException("Unknown failure. Received status code: " + statusCode); - } - } - - private static String urlEncode(final String s) { - return URLEncoder.encode(s, StandardCharsets.UTF_8); - } - - public static void main(String[] args) - { - final File file = new File("/home/viktor/Work/Projects/ETH/openbis/settings.gradle"); - uploadFileWorkspaceDss(new File[]{file}); - } - -} diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/OpenBISAPI.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/OpenBISAPI.java index 70987290eef62e1056ad40d1d605f78439a125eb..5fadcf3663b5da19305ad71c941a4ace3eb52de1 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/OpenBISAPI.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/OpenBISAPI.java @@ -4,38 +4,149 @@ import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; +import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.spring.HttpInvokerUtils; +import java.io.File; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; +import java.util.Map; +import java.util.Objects; + +import com.fasterxml.jackson.databind.ObjectMapper; public class OpenBISAPI { + private static final int DEFAULT_TIMEOUT_IN_MILLIS = 30000; //30 seconds + private static final int CHUNK_SIZE = 1048576; + private final IApplicationServerApi asFacade; + private final IDataStoreServerApi dssFacade; + private String sessionToken; - public OpenBISAPI(String asURL, String dssURL, int timeout) { - asFacade = HttpInvokerUtils.createServiceStub(IApplicationServerApi.class, asURL, timeout); - dssFacade = HttpInvokerUtils.createServiceStub(IDataStoreServerApi.class, dssURL, timeout); + private final int timeout; + + private final String asURL; + + private final String dssURL; + + public OpenBISAPI(final String asURL, final String dssURL) { + this(asURL, dssURL, DEFAULT_TIMEOUT_IN_MILLIS); + } + + public OpenBISAPI(final String asURL, final String dssURL, final int timeout) { + this.timeout = timeout; + this.asURL = asURL; + asFacade = HttpInvokerUtils.createServiceStub(IApplicationServerApi.class, this.asURL, timeout); + this.dssURL = dssURL; + dssFacade = HttpInvokerUtils.createServiceStub(IDataStoreServerApi.class, this.dssURL, timeout); } public String getSessionToken() { return sessionToken; } - public void setSessionToken(String sessionToken) { + public void setSessionToken(final String sessionToken) { this.sessionToken = sessionToken; } - public String uploadFileWorkspaceDSS(Path fileOrFolder) { - // Upload file or folder to the DSS SessionWorkspaceFileUploadServlet and return the ID to be used by createUploadedDataSet - // This method hides the complexities of uploading a folder with many files and does the uploads in chunks. - return null; + /** + * Upload file or folder to the DSS SessionWorkspaceFileUploadServlet and return the ID to be used by createUploadedDataSet + * This method hides the complexities of uploading a folder with many files and does the uploads in chunks. + */ + public String uploadFileWorkspaceDSS(final Path fileOrFolder) { + // final ServiceFinder serviceFinder = new ServiceFinder("openbis", "session_workspace_file_upload"); + // serviceFinder.computeServerUrl() + + Objects.requireNonNull(sessionToken); + + try + { + final File file = fileOrFolder.toFile(); + + if (!file.isFile()) + { + throw new UserFailureException("File must be a file for now."); + } + + final String fileName = file.getName(); + + final String response = request("POST", new URI(dssURL + "/session_workspace_file_upload"), + Map.of( + "sessionID", sessionToken, + "filename", fileName, + "id", "0", + "startByte", "0", + "endByte", String.valueOf(file.length()), + "size", String.valueOf(file.length()) + ), Files.readAllBytes(file.toPath())); + System.out.println(response); + + @SuppressWarnings("unchecked") + final Map<String, String> values = new ObjectMapper().readValue(response, Map.class); + + return values.get("uploadID"); + } catch (Exception e) + { + throw new RuntimeException(e); + } } - public DataSetPermId createUploadedDataSet(UploadedDataSetCreation newDataSet) { + public DataSetPermId createUploadedDataSet(final UploadedDataSetCreation newDataSet) { return dssFacade.createUploadedDataSet(sessionToken, newDataSet); } + @SuppressWarnings({ "OptionalGetWithoutIsPresent", "unchecked" }) + private String request(final String httpMethod, final URI serverUri, + final Map<String, String> parameters, final byte [] body) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_1_1) + .followRedirects(HttpClient.Redirect.NORMAL) + .connectTimeout(Duration.ofMillis(timeout)) + .build(); + + final String query = parameters.entrySet().stream() + .map(entry -> urlEncode(entry.getKey()) + "=" + urlEncode(entry.getValue())) + .reduce((s1, s2) -> s1 + "&" + s2).get(); + + final URI uri = new URI(serverUri.getScheme(), null, serverUri.getHost(), serverUri.getPort(), + serverUri.getPath(), query, null); + + final HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(uri) + .version(HttpClient.Version.HTTP_1_1) + .timeout(Duration.ofMillis(timeout)) + .method(httpMethod, HttpRequest.BodyPublishers.ofByteArray(body)); + + final HttpRequest request = builder.build(); + + final HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString()); + + final int statusCode = httpResponse.statusCode(); + if (statusCode >= 200 && statusCode < 300) { + return httpResponse.body(); + } else if (statusCode >= 400 && statusCode < 500) { + throw new UserFailureException("User failure. Received status code: " + statusCode + ". Body: " + + new String(httpResponse.body())); + } else if (statusCode >= 500 && statusCode < 600) { + throw new RuntimeException("Server failure. Received status code: " + statusCode); + } else { + throw new RuntimeException("Unknown failure. Received status code: " + statusCode); + } + } + + private static String urlEncode(final String s) { + return URLEncoder.encode(s, StandardCharsets.UTF_8); + } + }