diff --git a/pom.xml b/pom.xml index 5bf1e0b5..6b786a57 100644 --- a/pom.xml +++ b/pom.xml @@ -266,10 +266,6 @@ spring-security-jwt 1.0.9.RELEASE - - org.springframework.boot - spring-boot-starter-webflux - diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/AbstractDownloadServiceHandler.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/AbstractDownloadServiceHandler.java index f7e5dfec..ce884b46 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/AbstractDownloadServiceHandler.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/AbstractDownloadServiceHandler.java @@ -8,6 +8,8 @@ package ch.ethz.seb.sebserver.gui.service.remote; +import java.io.OutputStream; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -49,25 +51,32 @@ public abstract class AbstractDownloadServiceHandler implements DownloadServiceH configId, downloadFileName); - final byte[] configFile = webserviceCall(configId); - - if (configFile == null) { - log.error("No or empty download received from webservice. Download request is ignored"); - return; - } - - log.debug("Sucessfully downloaded from webservice. File size: {}", configFile.length); - - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); - response.setContentLength(configFile.length); - final String header = "attachment; filename=\"" + Utils.preventResponseSplittingAttack(downloadFileName) + "\""; response.setHeader(HttpHeaders.CONTENT_DISPOSITION, header); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); - log.debug("Write the download data to response output"); + webserviceCall(configId, response.getOutputStream()); - response.getOutputStream().write(configFile); +// final byte[] configFile = webserviceCall(configId); +// +// if (configFile == null) { +// log.error("No or empty download received from webservice. Download request is ignored"); +// return; +// } +// +// log.debug("Sucessfully downloaded from webservice. File size: {}", configFile.length); +// +// response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); +// response.setContentLength(configFile.length); +// +// final String header = +// "attachment; filename=\"" + Utils.preventResponseSplittingAttack(downloadFileName) + "\""; +// response.setHeader(HttpHeaders.CONTENT_DISPOSITION, header); +// +// log.debug("Write the download data to response output"); +// +// response.getOutputStream().write(configFile); } catch (final Exception e) { log.error( @@ -76,6 +85,6 @@ public abstract class AbstractDownloadServiceHandler implements DownloadServiceH } } - protected abstract byte[] webserviceCall(String configId); + protected abstract void webserviceCall(String configId, OutputStream downloadOut); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/SebClientConfigDownload.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/SebClientConfigDownload.java index 3774d8cc..af1a69a3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/SebClientConfigDownload.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/SebClientConfigDownload.java @@ -8,6 +8,13 @@ package ch.ethz.seb.sebserver.gui.service.remote; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -22,6 +29,8 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig. @GuiProfile public class SebClientConfigDownload extends AbstractDownloadServiceHandler { + private static final Logger log = LoggerFactory.getLogger(SebClientConfigDownload.class); + private final RestService restService; public final String downloadFileName; @@ -34,11 +43,27 @@ public class SebClientConfigDownload extends AbstractDownloadServiceHandler { } @Override - protected byte[] webserviceCall(final String modelId) { - return this.restService.getBuilder(ExportClientConfig.class) + protected void webserviceCall(final String modelId, final OutputStream downloadOut) { + + final InputStream input = this.restService.getBuilder(ExportClientConfig.class) .withURIVariable(API.PARAM_MODEL_ID, modelId) .call() .getOrThrow(); + + try { + IOUtils.copyLarge(input, downloadOut); + } catch (final IOException e) { + log.error( + "Unexpected error while streaming incomming config data from web-service to output-stream of download response: ", + e); + } finally { + try { + downloadOut.flush(); + downloadOut.close(); + } catch (final IOException e) { + log.error("Unexpected error while trying to close download output-stream"); + } + } } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/SebExamConfigDownload.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/SebExamConfigDownload.java index 2f5981e3..c65038d7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/SebExamConfigDownload.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/SebExamConfigDownload.java @@ -8,6 +8,13 @@ package ch.ethz.seb.sebserver.gui.service.remote; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -21,6 +28,8 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.Ex @GuiProfile public class SebExamConfigDownload extends AbstractDownloadServiceHandler { + private static final Logger log = LoggerFactory.getLogger(SebExamConfigDownload.class); + private final RestService restService; protected SebExamConfigDownload(final RestService restService) { @@ -28,11 +37,27 @@ public class SebExamConfigDownload extends AbstractDownloadServiceHandler { } @Override - protected byte[] webserviceCall(final String modelId) { - return this.restService.getBuilder(ExportPlainXML.class) + protected void webserviceCall(final String modelId, final OutputStream downloadOut) { + + final InputStream input = this.restService.getBuilder(ExportPlainXML.class) .withURIVariable(API.PARAM_MODEL_ID, modelId) .call() .getOrThrow(); + + try { + IOUtils.copyLarge(input, downloadOut); + } catch (final IOException e) { + log.error( + "Unexpected error while streaming incomming config data from web-service to output-stream of download response: ", + e); + } finally { + try { + downloadOut.flush(); + downloadOut.close(); + } catch (final IOException e) { + log.error("Unexpected error while trying to close download output-stream"); + } + } } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/AbstractExportCall.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/AbstractExportCall.java index d7f3a307..84f341d0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/AbstractExportCall.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/AbstractExportCall.java @@ -8,25 +8,19 @@ package ch.ethz.seb.sebserver.gui.service.remote.webservice.api; -import java.io.IOException; +import java.io.InputStream; -import org.apache.http.HttpHeaders; -import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream; -import org.apache.tomcat.util.http.fileupload.IOUtils; -import org.springframework.core.io.buffer.DataBuffer; +import org.apache.commons.io.IOUtils; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.security.oauth2.client.OAuth2RestTemplate; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.client.ClientHttpRequest; import ch.ethz.seb.sebserver.gbl.util.Result; -public abstract class AbstractExportCall extends RestCall { +public abstract class AbstractExportCall extends RestCall { protected AbstractExportCall( - final TypeKey typeKey, + final TypeKey typeKey, final HttpMethod httpMethod, final MediaType contentType, final String path) { @@ -34,85 +28,22 @@ public abstract class AbstractExportCall extends RestCall { super(typeKey, httpMethod, contentType, path); } - // We need a WebClient here to separate the request from the usual RestTemplate - // and allow also to get async responses - // The OAut2 bearer is get from the current OAuth2RestTemplate - // TODO create better API for this on RestCallBuilder site @Override - protected Result exchange(final RestCallBuilder builder) { - try { + protected Result exchange(final RestCallBuilder builder) { - final OAuth2RestTemplate restTemplate = (OAuth2RestTemplate) builder.getRestTemplate(); - final OAuth2AccessToken accessToken = restTemplate.getAccessToken(); - final String value = accessToken.getValue(); + return Result.tryCatch(() -> { - final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - WebClient.create() - .method(this.httpMethod) - .uri( + return builder + .getRestTemplate() + .execute( builder.buildURI(), - builder.getURIVariables()) - .header(HttpHeaders.AUTHORIZATION, "Bearer " + value) - .headers(h -> h.addAll(builder.buildRequestEntity().getHeaders())) - .body(BodyInserters.fromObject("grant_type=client_credentials&scope=read,write")) - .accept(MediaType.APPLICATION_OCTET_STREAM) - .retrieve() - .bodyToFlux(DataBuffer.class) - .map(source -> { + this.httpMethod, + (final ClientHttpRequest requestCallback) -> { + }, + response -> IOUtils.toBufferedInputStream(response.getBody()), + builder.getURIVariables()); - try { - IOUtils.copyLarge(source.asInputStream(), byteArrayOutputStream); - } catch (final IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return source; - }) - .blockLast(); - - final byte[] byteArray = byteArrayOutputStream.toByteArray(); - - return Result.of(byteArray); - -// final byte[] value = builder -// .getRestTemplate() -// .execute( -// builder.buildURI(), -// this.httpMethod, -// request -> { -// }, -// response -> { -// final InputStream input = IOUtils.toBufferedInputStream(response.getBody()); -// final ByteArrayOutputStream output = new ByteArrayOutputStream(); -// IOUtils.copyLarge(input, output); -// return output.toByteArray(); -// }, -// builder.getURIVariables()); -// -// System.out.println("************************ getResponse " + Utils.toString(value)); -// -// return Result.of(value); -// -// final ResponseEntity responseEntity = builder -// .getRestTemplate() -// .exchange( -// builder.buildURI(), -// this.httpMethod, -// builder.buildRequestEntity(), -// byte[].class, -// builder.getURIVariables()); - -// if (responseEntity.getStatusCode() == HttpStatus.OK) { -// final byte[] body = responseEntity.getBody(); -// System.out.println("************************ getResponse " + Utils.toString(body)); -// return Result.of(body); -// } -// -// return Result.ofRuntimeError( -// "Error while trying to export from webservice. Response: " + responseEntity); - } catch (final Throwable t) { - return Result.ofError(t); - } + }); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/clientconfig/ExportClientConfig.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/clientconfig/ExportClientConfig.java index a53ad42a..39c11fce 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/clientconfig/ExportClientConfig.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/clientconfig/ExportClientConfig.java @@ -8,6 +8,8 @@ package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig; +import java.io.InputStream; + import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -29,7 +31,7 @@ public class ExportClientConfig extends AbstractExportCall { super(new TypeKey<>( CallType.UNDEFINED, EntityType.SEB_CLIENT_CONFIGURATION, - new TypeReference() { + new TypeReference() { }), HttpMethod.GET, MediaType.APPLICATION_FORM_URLENCODED, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/ExportPlainXML.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/ExportPlainXML.java index e43fab7e..8708736b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/ExportPlainXML.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/ExportPlainXML.java @@ -8,6 +8,8 @@ package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig; +import java.io.InputStream; + import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -29,7 +31,7 @@ public class ExportPlainXML extends AbstractExportCall { super(new TypeKey<>( CallType.UNDEFINED, EntityType.CONFIGURATION_NODE, - new TypeReference() { + new TypeReference() { }), HttpMethod.GET, MediaType.APPLICATION_FORM_URLENCODED,