change streaming support back to RestTemplate

This commit is contained in:
anhefti 2019-08-01 12:32:34 +02:00
parent 11c79d55d8
commit ccced32e1d
7 changed files with 100 additions and 110 deletions

View file

@ -266,10 +266,6 @@
<artifactId>spring-security-jwt</artifactId> <artifactId>spring-security-jwt</artifactId>
<version>1.0.9.RELEASE</version> <version>1.0.9.RELEASE</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Apache HTTP --> <!-- Apache HTTP -->
<dependency> <dependency>

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.gui.service.remote; package ch.ethz.seb.sebserver.gui.service.remote;
import java.io.OutputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -49,25 +51,32 @@ public abstract class AbstractDownloadServiceHandler implements DownloadServiceH
configId, configId,
downloadFileName); 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 = final String header =
"attachment; filename=\"" + Utils.preventResponseSplittingAttack(downloadFileName) + "\""; "attachment; filename=\"" + Utils.preventResponseSplittingAttack(downloadFileName) + "\"";
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, header); 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) { } catch (final Exception e) {
log.error( 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);
} }

View file

@ -8,6 +8,13 @@
package ch.ethz.seb.sebserver.gui.service.remote; 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.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -22,6 +29,8 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.
@GuiProfile @GuiProfile
public class SebClientConfigDownload extends AbstractDownloadServiceHandler { public class SebClientConfigDownload extends AbstractDownloadServiceHandler {
private static final Logger log = LoggerFactory.getLogger(SebClientConfigDownload.class);
private final RestService restService; private final RestService restService;
public final String downloadFileName; public final String downloadFileName;
@ -34,11 +43,27 @@ public class SebClientConfigDownload extends AbstractDownloadServiceHandler {
} }
@Override @Override
protected byte[] webserviceCall(final String modelId) { protected void webserviceCall(final String modelId, final OutputStream downloadOut) {
return this.restService.getBuilder(ExportClientConfig.class)
final InputStream input = this.restService.getBuilder(ExportClientConfig.class)
.withURIVariable(API.PARAM_MODEL_ID, modelId) .withURIVariable(API.PARAM_MODEL_ID, modelId)
.call() .call()
.getOrThrow(); .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");
}
}
} }
} }

View file

@ -8,6 +8,13 @@
package ch.ethz.seb.sebserver.gui.service.remote; 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.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -21,6 +28,8 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.Ex
@GuiProfile @GuiProfile
public class SebExamConfigDownload extends AbstractDownloadServiceHandler { public class SebExamConfigDownload extends AbstractDownloadServiceHandler {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigDownload.class);
private final RestService restService; private final RestService restService;
protected SebExamConfigDownload(final RestService restService) { protected SebExamConfigDownload(final RestService restService) {
@ -28,11 +37,27 @@ public class SebExamConfigDownload extends AbstractDownloadServiceHandler {
} }
@Override @Override
protected byte[] webserviceCall(final String modelId) { protected void webserviceCall(final String modelId, final OutputStream downloadOut) {
return this.restService.getBuilder(ExportPlainXML.class)
final InputStream input = this.restService.getBuilder(ExportPlainXML.class)
.withURIVariable(API.PARAM_MODEL_ID, modelId) .withURIVariable(API.PARAM_MODEL_ID, modelId)
.call() .call()
.getOrThrow(); .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");
}
}
} }
} }

View file

@ -8,25 +8,19 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api; 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.commons.io.IOUtils;
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.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.http.client.ClientHttpRequest;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
public abstract class AbstractExportCall extends RestCall<byte[]> { public abstract class AbstractExportCall extends RestCall<InputStream> {
protected AbstractExportCall( protected AbstractExportCall(
final TypeKey<byte[]> typeKey, final TypeKey<InputStream> typeKey,
final HttpMethod httpMethod, final HttpMethod httpMethod,
final MediaType contentType, final MediaType contentType,
final String path) { final String path) {
@ -34,85 +28,22 @@ public abstract class AbstractExportCall extends RestCall<byte[]> {
super(typeKey, httpMethod, contentType, path); 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 @Override
protected Result<byte[]> exchange(final RestCallBuilder builder) { protected Result<InputStream> exchange(final RestCallBuilder builder) {
try {
final OAuth2RestTemplate restTemplate = (OAuth2RestTemplate) builder.getRestTemplate(); return Result.tryCatch(() -> {
final OAuth2AccessToken accessToken = restTemplate.getAccessToken();
final String value = accessToken.getValue();
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); return builder
WebClient.create() .getRestTemplate()
.method(this.httpMethod) .execute(
.uri(
builder.buildURI(), builder.buildURI(),
builder.getURIVariables()) this.httpMethod,
.header(HttpHeaders.AUTHORIZATION, "Bearer " + value) (final ClientHttpRequest requestCallback) -> {
.headers(h -> h.addAll(builder.buildRequestEntity().getHeaders())) },
.body(BodyInserters.fromObject("grant_type=client_credentials&scope=read,write")) response -> IOUtils.toBufferedInputStream(response.getBody()),
.accept(MediaType.APPLICATION_OCTET_STREAM) builder.getURIVariables());
.retrieve()
.bodyToFlux(DataBuffer.class)
.map(source -> {
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<byte[]> 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);
}
} }
} }

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig; 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.context.annotation.Lazy;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -29,7 +31,7 @@ public class ExportClientConfig extends AbstractExportCall {
super(new TypeKey<>( super(new TypeKey<>(
CallType.UNDEFINED, CallType.UNDEFINED,
EntityType.SEB_CLIENT_CONFIGURATION, EntityType.SEB_CLIENT_CONFIGURATION,
new TypeReference<byte[]>() { new TypeReference<InputStream>() {
}), }),
HttpMethod.GET, HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig; 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.context.annotation.Lazy;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -29,7 +31,7 @@ public class ExportPlainXML extends AbstractExportCall {
super(new TypeKey<>( super(new TypeKey<>(
CallType.UNDEFINED, CallType.UNDEFINED,
EntityType.CONFIGURATION_NODE, EntityType.CONFIGURATION_NODE,
new TypeReference<byte[]>() { new TypeReference<InputStream>() {
}), }),
HttpMethod.GET, HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,