Commit 594b8f86 authored by Benaissa BENARBIA's avatar Benaissa BENARBIA Committed by Ro3034
Browse files

upgrade binary download to asynchronous download

parent 392f2d55
......@@ -139,14 +139,6 @@ public class ArchiveSearchExternalRestClient
}
public ResponseEntity<Resource> downloadObjectFromUnit(String id, String usage, Integer version, ExternalHttpContext context) {
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.DOWNLOAD_ARCHIVE_UNIT + CommonConstants.PATH_ID + "?usage=" + usage + "&version=" + version);
final HttpEntity<?> request = new HttpEntity<>(buildHeaders(context));
return restTemplate.exchange(uriBuilder.build(id), HttpMethod.GET, request, Resource.class);
}
public ResponseEntity<Resource> exportCsvArchiveUnitsByCriteria(SearchCriteriaDto query,
ExternalHttpContext context) {
LOGGER.debug("Calling export to csv search archives units by criteria");
......@@ -159,7 +151,8 @@ public class ArchiveSearchExternalRestClient
return response;
}
public ResponseEntity<String> exportDIPCriteria(ExportDipCriteriaDto exportDipCriteriaDto, ExternalHttpContext context) {
public ResponseEntity<String> exportDIPCriteria(ExportDipCriteriaDto exportDipCriteriaDto,
ExternalHttpContext context) {
LOGGER.debug("Calling export DIP by criteria");
MultiValueMap<String, String> headers = buildSearchHeaders(context);
final HttpEntity<ExportDipCriteriaDto> request = new HttpEntity<>(exportDipCriteriaDto, headers);
......@@ -185,7 +178,8 @@ public class ArchiveSearchExternalRestClient
request, JsonNode.class);
}
public ResponseEntity<String> updateArchiveUnitsRules(RuleSearchCriteriaDto ruleSearchCriteriaDto, ExternalHttpContext context) {
public ResponseEntity<String> updateArchiveUnitsRules(RuleSearchCriteriaDto ruleSearchCriteriaDto,
ExternalHttpContext context) {
LOGGER.debug("Calling updateArchiveUnitsRules by criteria");
MultiValueMap<String, String> headers = buildSearchHeaders(context);
final HttpEntity<RuleSearchCriteriaDto> request = new HttpEntity<>(ruleSearchCriteriaDto, headers);
......
......@@ -33,7 +33,14 @@ import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.commons.rest.client.BaseWebClient;
import fr.gouv.vitamui.commons.rest.client.ExternalHttpContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class ArchiveSearchExternalWebClient extends BaseWebClient<ExternalHttpContext> {
......@@ -47,4 +54,36 @@ public class ArchiveSearchExternalWebClient extends BaseWebClient<ExternalHttpCo
public String getPathUrl() {
return RestApi.ARCHIVE_SEARCH_PATH;
}
/**
* Download object from unit
*
* @param id unit id
* @param usage usage
* @param version version
* @param context internl context
* @return a mono<Response<Resourse>
**/
public Mono<ResponseEntity<Resource>> downloadObjectFromUnit(String id, final String usage, Integer version,
final ExternalHttpContext context) {
LOGGER.info("Start downloading Object from unit id : {} usage : {} version : {}", id, usage, version);
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.DOWNLOAD_ARCHIVE_UNIT + "/" + id + "?usage=" + usage +
"&version=" +
version);
Flux<DataBuffer> dataBuffer = webClient
.get()
.uri(uriBuilder.toUriString())
.headers(addHeaders(buildHeaders(context)))
.retrieve()
.bodyToFlux(DataBuffer.class);
return Mono.just(ResponseEntity
.ok().cacheControl(CacheControl.noCache())
.body(convertDataBufferFileToInputStreamResponse(dataBuffer)));
}
}
......@@ -27,19 +27,16 @@
package fr.gouv.vitamui.archives.search.external.client;
import fr.gouv.vitamui.commons.rest.client.BaseWebClientFactory;
import fr.gouv.vitamui.commons.rest.client.configuration.HttpPoolConfiguration;
import fr.gouv.vitamui.commons.rest.client.configuration.RestClientConfiguration;
import org.springframework.web.reactive.function.client.WebClient;
public class ArchiveSearchExternalWebClientFactory extends BaseWebClientFactory {
public ArchiveSearchExternalWebClientFactory(final RestClientConfiguration restClientConfiguration) {
super(restClientConfiguration);
public ArchiveSearchExternalWebClientFactory(final RestClientConfiguration restClientConfiguration,
final WebClient.Builder webClientBuilder) {
super(restClientConfiguration, webClientBuilder);
}
public ArchiveSearchExternalWebClientFactory(final RestClientConfiguration restClientConfig,
final HttpPoolConfiguration httpPoolConfig) {
super(restClientConfig, httpPoolConfig);
}
public ArchiveSearchExternalWebClient getArchiveSearchExternalWebClient() {
return new ArchiveSearchExternalWebClient(getWebClient(), getBaseUrl());
......
/**
* Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
* and the signatories of the "VITAM - Accord du Contributeur" agreement.
*
* contact@programmevitam.fr
*
* This software is a computer program whose purpose is to implement
* implement a digital archiving front-office system for the secure and
* efficient high volumetry VITAM solution.
*
* This software is governed by the CeCILL-C license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-C
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package fr.gouv.vitamui.archives.search.external.client;
import fr.gouv.vitamui.archives.search.common.rest.RestApi;
import fr.gouv.vitamui.commons.api.CommonConstants;
import fr.gouv.vitamui.commons.api.domain.PaginatedValuesDto;
import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.commons.rest.client.BasePaginatingAndSortingRestClient;
import fr.gouv.vitamui.commons.rest.client.ExternalHttpContext;
import fr.gouv.vitamui.commons.vitam.api.dto.LogbookOperationDto;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
/**
* A REST client to get logbooks for an External API.
*/
public class ArchiveSearchStreamingExternalRestClient
extends BasePaginatingAndSortingRestClient<LogbookOperationDto, ExternalHttpContext> {
private static final VitamUILogger LOGGER =
VitamUILoggerFactory.getInstance(ArchiveSearchStreamingExternalRestClient.class);
public ArchiveSearchStreamingExternalRestClient(final RestTemplate restTemplate, final String baseUrl) {
super(restTemplate, baseUrl);
}
@Override
public String getPathUrl() {
return RestApi.ARCHIVE_SEARCH_PATH;
}
@Override
protected Class<LogbookOperationDto> getDtoClass() {
return LogbookOperationDto.class;
}
@Override
protected ParameterizedTypeReference<List<LogbookOperationDto>> getDtoListClass() {
return new ParameterizedTypeReference<List<LogbookOperationDto>>() {
};
}
@Override
protected ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>> getDtoPaginatedClass() {
return new ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>>() {
};
}
public ResponseEntity<Resource> downloadObjectFromUnit(String id, String usage, Integer version,
ExternalHttpContext context) {
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(
getUrl() + RestApi.DOWNLOAD_ARCHIVE_UNIT + CommonConstants.PATH_ID + "?usage=" + usage + "&version=" +
version);
final HttpEntity<?> request = new HttpEntity<>(buildHeaders(context));
ResponseEntity<Resource> responseEntity =
restTemplate.exchange(uriBuilder.build(id), HttpMethod.GET, request, Resource.class);
ResponseEntity<Resource> result = ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM).body(responseEntity.getBody());
return result;
}
}
/**
* Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
* and the signatories of the "VITAM - Accord du Contributeur" agreement.
*
* contact@programmevitam.fr
*
* This software is a computer program whose purpose is to implement
* implement a digital archiving front-office system for the secure and
* efficient high volumetry VITAM solution.
*
* This software is governed by the CeCILL-C license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-C
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package fr.gouv.vitamui.archives.search.external.client;
import fr.gouv.vitamui.commons.rest.client.BaseStreamingRestClientFactory;
import fr.gouv.vitamui.commons.rest.client.configuration.RestClientConfiguration;
/**
* A Rest client factory to create Streaming specialized Archive search Rest clients
*/
public class ArchiveSearchStreamingExternalRestClientFactory extends BaseStreamingRestClientFactory {
public ArchiveSearchStreamingExternalRestClientFactory(final RestClientConfiguration restClientConfiguration) {
super(restClientConfiguration);
}
public ArchiveSearchStreamingExternalRestClient getIngestStreamingExternalRestClient() {
return new ArchiveSearchStreamingExternalRestClient(getRestTemplate(), getBaseUrl());
}
}
......@@ -28,8 +28,10 @@ package fr.gouv.vitamui.archives.search.external.server.config;
import fr.gouv.archive.internal.client.ArchiveInternalRestClient;
import fr.gouv.archive.internal.client.ArchiveInternalRestClientFactory;
import fr.gouv.archive.internal.client.ArchiveInternalWebClient;
import fr.gouv.archive.internal.client.ArchiveInternalWebClientFactory;
import fr.gouv.archive.internal.client.ArchiveSearchInternalWebClient;
import fr.gouv.archive.internal.client.ArchiveSearchInternalWebClientFactory;
import fr.gouv.archive.internal.client.ArchiveSearchStreamingInternalRestClient;
import fr.gouv.archive.internal.client.ArchiveSearchStreamingInternalRestClientFactory;
import fr.gouv.archive.internal.client.SearchCriteriaHistoryInternalRestClient;
import fr.gouv.vitamui.commons.api.application.AbstractContextConfiguration;
import fr.gouv.vitamui.commons.rest.RestExceptionHandler;
......@@ -97,6 +99,19 @@ public class ApiArchiveServerConfig extends AbstractContextConfiguration {
return iamInternalRestClientFactory.getUserInternalRestClient();
}
@Bean
public ArchiveSearchStreamingInternalRestClientFactory archiveSearchStreamingInternalRestClientFactory(
final ApiArchiveExternalApplicationProperties apiArchiveExternalApplicationProperties) {
return new ArchiveSearchStreamingInternalRestClientFactory(
apiArchiveExternalApplicationProperties.getArchiveSearchInternalClient());
}
@Bean
public ArchiveSearchStreamingInternalRestClient archiveSearchStreamingInternalRestClient(
final ArchiveSearchStreamingInternalRestClientFactory factory) {
return factory.getArchiveSearchStreamingInternalRestClient();
}
@Bean
public ArchiveInternalRestClientFactory archiveInternalRestClientFactory(
final ApiArchiveExternalApplicationProperties apiArchiveExternalApplicationProperties,
......@@ -105,6 +120,8 @@ public class ApiArchiveServerConfig extends AbstractContextConfiguration {
apiArchiveExternalApplicationProperties.getArchiveSearchInternalClient(), restTemplateBuilder);
}
@Bean
public ArchiveInternalRestClient archiveInternalRestClient(
final ArchiveInternalRestClientFactory factory) {
......@@ -112,17 +129,17 @@ public class ApiArchiveServerConfig extends AbstractContextConfiguration {
}
@Bean
public ArchiveInternalWebClientFactory archiveInternalWebClientFactory(
public ArchiveSearchInternalWebClientFactory archiveInternalWebClientFactory(
final ApiArchiveExternalApplicationProperties apiArchiveExternalApplicationProperties,
final RestTemplateBuilder restTemplateBuilder) {
return new ArchiveInternalWebClientFactory(
return new ArchiveSearchInternalWebClientFactory(
apiArchiveExternalApplicationProperties.getArchiveSearchInternalClient());
}
@Bean
public ArchiveInternalWebClient archiveInternalWebClient(
final ArchiveInternalWebClientFactory factory) {
public ArchiveSearchInternalWebClient archiveInternalWebClient(
final ArchiveSearchInternalWebClientFactory factory) {
return factory.getArchiveInternalWebClient();
}
......@@ -131,4 +148,5 @@ public class ApiArchiveServerConfig extends AbstractContextConfiguration {
final ArchiveInternalRestClientFactory archiveInternalRestClientFactory) {
return archiveInternalRestClientFactory.getSearchCriteriaHistoryInternalRestClient();
}
}
......@@ -45,6 +45,7 @@ import fr.gouv.vitamui.commons.vitam.api.dto.VitamUISearchResponseDto;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.GetMapping;
......@@ -55,6 +56,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
/**
......@@ -91,9 +93,10 @@ public class ArchivesSearchExternalController {
return archivesSearchExternalService.getFilingHoldingScheme();
}
@GetMapping(RestApi.DOWNLOAD_ARCHIVE_UNIT + CommonConstants.PATH_ID)
@GetMapping(value = RestApi.DOWNLOAD_ARCHIVE_UNIT +
CommonConstants.PATH_ID, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@Secured(ServicesData.ROLE_GET_ARCHIVE)
public ResponseEntity<Resource> downloadObjectFromUnit(final @PathVariable("id") String id,
public Mono<ResponseEntity<Resource>> downloadObjectFromUnit(final @PathVariable("id") String id,
final @RequestParam("usage") String usage, final @RequestParam("version") Integer version) {
LOGGER.info("Download the Archive Unit Object with id {} ", id);
ParameterChecker.checkParameter("The Identifier is a mandatory parameter: ", id);
......
......@@ -29,7 +29,7 @@ package fr.gouv.vitamui.archives.search.external.server.service;
import com.fasterxml.jackson.databind.JsonNode;
import fr.gouv.archive.internal.client.ArchiveInternalRestClient;
import fr.gouv.archive.internal.client.ArchiveInternalWebClient;
import fr.gouv.archive.internal.client.ArchiveSearchInternalWebClient;
import fr.gouv.vitamui.archives.search.common.dto.ArchiveUnitsDto;
import fr.gouv.vitamui.archives.search.common.dto.ExportDipCriteriaDto;
import fr.gouv.vitamui.archives.search.common.dto.RuleSearchCriteriaDto;
......@@ -44,6 +44,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
/**
......@@ -57,15 +58,16 @@ public class ArchivesSearchExternalService extends AbstractResourceClientService
@Autowired
private final ArchiveInternalRestClient archiveInternalRestClient;
@Autowired
private final ArchiveInternalWebClient archiveInternalWebClient;
private final ArchiveSearchInternalWebClient archiveSearchInternalWebClient;
public ArchivesSearchExternalService(@Autowired ArchiveInternalRestClient archiveInternalRestClient,
ArchiveInternalWebClient archiveInternalWebClient,
ArchiveSearchInternalWebClient archiveSearchInternalWebClient,
final ExternalSecurityService externalSecurityService) {
super(externalSecurityService);
this.archiveInternalRestClient = archiveInternalRestClient;
this.archiveInternalWebClient = archiveInternalWebClient;
this.archiveSearchInternalWebClient = archiveSearchInternalWebClient;
}
@Override
......@@ -90,8 +92,9 @@ public class ArchivesSearchExternalService extends AbstractResourceClientService
return archiveInternalRestClient.getFilingHoldingScheme(getInternalHttpContext());
}
public ResponseEntity<Resource> downloadObjectFromUnit(String id, String usage, Integer version) {
return archiveInternalRestClient.downloadObjectFromUnit(id, usage, version, getInternalHttpContext());
public Mono<ResponseEntity<Resource>> downloadObjectFromUnit(String id, String usage, Integer version) {
return archiveSearchInternalWebClient
.downloadObjectFromUnit(id, usage, version, getInternalHttpContext());
}
public Resource exportCsvArchiveUnitsByCriteria(final SearchCriteriaDto query) {
......
......@@ -126,13 +126,6 @@ public class ArchiveInternalRestClient
return headers;
}
public ResponseEntity<Resource> downloadObjectFromUnit(String id, final String usage, Integer version, final InternalHttpContext context) {
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.DOWNLOAD_ARCHIVE_UNIT + CommonConstants.PATH_ID + "?usage=" + usage + "&version=" + version);
final HttpEntity<?> request = new HttpEntity<>(buildHeaders(context));
return restTemplate.exchange(uriBuilder.build(id), HttpMethod.GET, request, Resource.class);
}
public ResponseEntity<ResultsDto> findUnitById(String id, final InternalHttpContext context) {
final UriComponentsBuilder uriBuilder =
......@@ -162,7 +155,7 @@ public class ArchiveInternalRestClient
}
public String exportDIPByCriteria(final ExportDipCriteriaDto exportDipCriteriaDto,
final InternalHttpContext context) {
final InternalHttpContext context) {
LOGGER.info("Calling exportDIPByCriteria with query {} ", exportDipCriteriaDto);
MultiValueMap<String, String> headers = buildSearchHeaders(context);
final HttpEntity<ExportDipCriteriaDto> request = new HttpEntity<>(exportDipCriteriaDto, headers);
......@@ -174,7 +167,8 @@ public class ArchiveInternalRestClient
}
public ResponseEntity<JsonNode> startEliminationAnalysis(final InternalHttpContext context, final SearchCriteriaDto query) {
public ResponseEntity<JsonNode> startEliminationAnalysis(final InternalHttpContext context,
final SearchCriteriaDto query) {
LOGGER.info("Calling elimination analysis with query {} ", query);
MultiValueMap<String, String> headers = buildSearchHeaders(context);
final HttpEntity<SearchCriteriaDto> request = new HttpEntity<>(query, headers);
......@@ -186,7 +180,8 @@ public class ArchiveInternalRestClient
}
public ResponseEntity<JsonNode> startEliminationAction(final InternalHttpContext context, final SearchCriteriaDto query) {
public ResponseEntity<JsonNode> startEliminationAction(final InternalHttpContext context,
final SearchCriteriaDto query) {
LOGGER.info("Calling elimination action with query {} ", query);
MultiValueMap<String, String> headers = buildSearchHeaders(context);
final HttpEntity<SearchCriteriaDto> request = new HttpEntity<>(query, headers);
......
......@@ -31,13 +31,20 @@ import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.commons.rest.client.BaseWebClient;
import fr.gouv.vitamui.commons.rest.client.InternalHttpContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class ArchiveInternalWebClient extends BaseWebClient<InternalHttpContext> {
public class ArchiveSearchInternalWebClient extends BaseWebClient<InternalHttpContext> {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(ArchiveInternalWebClient.class);
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(ArchiveSearchInternalWebClient.class);
public ArchiveInternalWebClient(final WebClient webClient, final String baseUrl) {
public ArchiveSearchInternalWebClient(final WebClient webClient, final String baseUrl) {
super(webClient, baseUrl);
}
......@@ -45,4 +52,38 @@ public class ArchiveInternalWebClient extends BaseWebClient<InternalHttpContext>
public String getPathUrl() {
return RestApi.ARCHIVE_SEARCH_PATH;
}
/**
* Download object from unit
*
* @param id unit id
* @param usage usage
* @param version version
* @param context internl context
* @return a mono<Response<Resourse>
*/
public Mono<ResponseEntity<Resource>> downloadObjectFromUnit(String id, final String usage, Integer version,
final InternalHttpContext context) {
LOGGER.info("Start downloading Object from unit id : {} usage : {} version : {}", id, usage, version);
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(
getUrl() + RestApi.DOWNLOAD_ARCHIVE_UNIT + "/" + id + "?usage=" + usage +
"&version=" +
version);
Flux<DataBuffer> dataBuffer = webClient
.get()
.uri(uriBuilder.toUriString())
.headers(addHeaders(buildHeaders(context)))
.retrieve()
.bodyToFlux(DataBuffer.class);
return Mono.just(ResponseEntity
.ok().cacheControl(CacheControl.noCache())