Skip to content
Snippets Groups Projects
Unverified Commit 4c0cae8a authored by eric969's avatar eric969 Committed by GitHub
Browse files

Merge pull request #321 from ProgrammeVitam/vas_bug_7638_replace_ingest_critical_bug_by_streaming

[Vas] Bug 7638 : Correction du bug critique d'ingest en mode streaming
parents 06ae6c2a 83df5d5d
No related branches found
No related tags found
10 merge requests!51Merge mis a jour vitam-ui,!25Nouveau mis a jour Vitamui,!24Nouveau mis a jour Vitamui,!23Nouveau mis a jour Vitamui,!22WIP: nouveau mis a jour Vitamui,!21nouveau mis a jour Vitamui,!20nouveau mis à jour Vitamui,!19nouveau mis à jour Vitamui,!18New MAJ Vitamui,!16[VAS] BUG 7332 : Correction sur la position de la barre permettant de...
Showing
with 870 additions and 219 deletions
......@@ -29,6 +29,7 @@ package fr.gouv.vitamui.ingest.common.rest;
public class RestApi {
public static final String V1_INGEST = "/iam/v1/ingest";
public static final String INGEST_REPORT_ODT = "/odtreport";
public static final String INGEST_UPLOAD_V2 = "/upload-v2";
public static final String INGEST_ATR = "/atr";
public static final String INGEST_MANIFEST = "/manifest";
}
......@@ -57,7 +57,8 @@ import java.util.List;
/**
* A REST client to get logbooks for an External API.
*/
public class IngestExternalRestClient extends BasePaginatingAndSortingRestClient<LogbookOperationDto, ExternalHttpContext> {
public class IngestExternalRestClient
extends BasePaginatingAndSortingRestClient<LogbookOperationDto, ExternalHttpContext> {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(IngestExternalRestClient.class);
......@@ -70,22 +71,27 @@ public class IngestExternalRestClient extends BasePaginatingAndSortingRestClient
return RestApi.V1_INGEST;
}
@Override protected Class<LogbookOperationDto> getDtoClass() {
@Override
protected Class<LogbookOperationDto> getDtoClass() {
return LogbookOperationDto.class;
}
@Override protected ParameterizedTypeReference<List<LogbookOperationDto>> getDtoListClass() {
return new ParameterizedTypeReference<List<LogbookOperationDto>>() {};
@Override
protected ParameterizedTypeReference<List<LogbookOperationDto>> getDtoListClass() {
return new ParameterizedTypeReference<List<LogbookOperationDto>>() {
};
}
@Override protected ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>> getDtoPaginatedClass() {
return new ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>>() {};
@Override
protected ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>> getDtoPaginatedClass() {
return new ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>>() {
};
}
public ResponseEntity<byte[]> generateODTReport(ExternalHttpContext context, String id) {
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.INGEST_REPORT_ODT + CommonConstants.PATH_ID );
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.INGEST_REPORT_ODT + CommonConstants.PATH_ID);
final HttpEntity<AuditOptions> request = new HttpEntity<>(buildHeaders(context));
return restTemplate.exchange(uriBuilder.build(id), HttpMethod.GET, request, byte[].class);
}
}
......@@ -39,6 +39,7 @@ package fr.gouv.vitamui.ingest.external.client;
import fr.gouv.vitamui.commons.rest.client.BaseRestClientFactory;
import fr.gouv.vitamui.commons.rest.client.configuration.HttpPoolConfiguration;
import fr.gouv.vitamui.commons.rest.client.configuration.RestClientConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.client.RestTemplateBuilder;
/**
......
/**
* 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.ingest.external.client;
import fr.gouv.vitam.common.model.AuditOptions;
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 fr.gouv.vitamui.ingest.common.rest.RestApi;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.InputStream;
import java.util.List;
/**
* A REST client to get logbooks for an External API.
*/
public class IngestStreamingExternalRestClient
extends BasePaginatingAndSortingRestClient<LogbookOperationDto, ExternalHttpContext> {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(IngestStreamingExternalRestClient.class);
public IngestStreamingExternalRestClient(final RestTemplate restTemplate, final String baseUrl) {
super(restTemplate, baseUrl);
}
@Override
public String getPathUrl() {
return RestApi.V1_INGEST;
}
@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<Void> streamingUpload(final ExternalHttpContext context, String fileName,
InputStream inputStream,
final String contextId,
final String action) {
LOGGER.debug("Calling upload using streaming process");
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.INGEST_UPLOAD_V2);
final MultiValueMap<String, String> headersList = new HttpHeaders();
headersList.addAll(buildHeaders(context));
headersList.add(CommonConstants.X_CONTEXT_ID, contextId);
headersList.add(CommonConstants.X_ACTION, action);
headersList.add(CommonConstants.X_ORIGINAL_FILENAME_HEADER, fileName);
HttpHeaders headersParams = new HttpHeaders();
headersParams.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headersParams.addAll(headersList);
final HttpEntity<InputStreamResource> request =
new HttpEntity<>(new InputStreamResource(inputStream), headersParams);
final ResponseEntity<Void> response =
restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.POST,
request, Void.class);
LOGGER.info("The response is {}", response.toString());
return response;
}
}
/**
* 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.ingest.external.client;
import fr.gouv.vitamui.commons.rest.client.BaseRestClientFactory;
import fr.gouv.vitamui.commons.rest.client.BaseStreamingRestClientFactory;
import fr.gouv.vitamui.commons.rest.client.configuration.HttpPoolConfiguration;
import fr.gouv.vitamui.commons.rest.client.configuration.RestClientConfiguration;
import org.springframework.boot.web.client.RestTemplateBuilder;
/**
* A Rest client factory to create Streaming specialized Ingest Rest clients
*
*
*/
public class IngestStreamingExternalRestClientFactory extends BaseStreamingRestClientFactory {
public IngestStreamingExternalRestClientFactory(final RestClientConfiguration restClientConfiguration) {
super(restClientConfiguration);
}
public IngestStreamingExternalRestClientFactory(final RestClientConfiguration restClientConfiguration, final HttpPoolConfiguration httpHostConfiguration) {
super(restClientConfiguration, httpHostConfiguration);
}
public IngestStreamingExternalRestClient getIngestStreamingExternalRestClient() {
return new IngestStreamingExternalRestClient(getRestTemplate(), getBaseUrl());
}
}
......@@ -11,12 +11,6 @@ spring:
enabled: false
register: false
multipart:
enabled: true
spring.servlet.multipart.max-file-size: -1
spring.servlet.multipart.max-request-size: -1
server-identity:
identityName: vitamui-dev
identityRole: ingest-external
......
......@@ -48,6 +48,8 @@ import fr.gouv.vitamui.ingest.internal.client.IngestInternalRestClient;
import fr.gouv.vitamui.ingest.internal.client.IngestInternalRestClientFactory;
import fr.gouv.vitamui.ingest.internal.client.IngestInternalWebClient;
import fr.gouv.vitamui.ingest.internal.client.IngestInternalWebClientFactory;
import fr.gouv.vitamui.ingest.internal.client.IngestStreamingInternalRestClient;
import fr.gouv.vitamui.ingest.internal.client.IngestStreamingInternalRestClientFactory;
import fr.gouv.vitamui.security.client.ContextRestClient;
import fr.gouv.vitamui.security.client.SecurityRestClientFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
......@@ -55,15 +57,21 @@ import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import java.util.Arrays;
@Configuration
@Import({RestExceptionHandler.class, SwaggerConfiguration.class, HttpMessageConvertersAutoConfiguration.class})
public class ApiIngestServerConfig extends AbstractContextConfiguration {
@Bean
public SecurityRestClientFactory securityRestClientFactory(final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties,
final RestTemplateBuilder restTemplateBuilder) {
return new SecurityRestClientFactory(apiIngestExternalApplicationProperties.getSecurityClient(), restTemplateBuilder);
public SecurityRestClientFactory securityRestClientFactory(
final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties,
final RestTemplateBuilder restTemplateBuilder) {
return new SecurityRestClientFactory(apiIngestExternalApplicationProperties.getSecurityClient(),
restTemplateBuilder);
}
@Bean
......@@ -72,7 +80,19 @@ public class ApiIngestServerConfig extends AbstractContextConfiguration {
}
@Bean
public ExternalApiAuthenticationProvider apiAuthenticationProvider(final ExternalAuthentificationService externalAuthentificationService) {
public MappingJackson2HttpMessageConverter customizedJacksonMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(
Arrays.asList(
MediaType.APPLICATION_JSON,
new MediaType("application", "*+json"),
MediaType.APPLICATION_OCTET_STREAM));
return converter;
}
@Bean
public ExternalApiAuthenticationProvider apiAuthenticationProvider(
final ExternalAuthentificationService externalAuthentificationService) {
return new ExternalApiAuthenticationProvider(externalAuthentificationService);
}
......@@ -83,28 +103,46 @@ public class ApiIngestServerConfig extends AbstractContextConfiguration {
@Bean
public ExternalAuthentificationService externalAuthentificationService(final ContextRestClient contextRestClient,
final UserInternalRestClient userInternalRestClient) {
final UserInternalRestClient userInternalRestClient) {
return new ExternalAuthentificationService(contextRestClient, userInternalRestClient);
}
@Bean
public IamInternalRestClientFactory iamInternalRestClientFactory(final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties,
final RestTemplateBuilder restTemplateBuilder) {
return new IamInternalRestClientFactory(apiIngestExternalApplicationProperties.getIamInternalClient(), restTemplateBuilder);
public IamInternalRestClientFactory iamInternalRestClientFactory(
final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties,
final RestTemplateBuilder restTemplateBuilder) {
return new IamInternalRestClientFactory(apiIngestExternalApplicationProperties.getIamInternalClient(),
restTemplateBuilder);
}
@Bean
public UserInternalRestClient userInternalRestClient(final IamInternalRestClientFactory iamInternalRestClientFactory) {
public UserInternalRestClient userInternalRestClient(
final IamInternalRestClientFactory iamInternalRestClientFactory) {
return iamInternalRestClientFactory.getUserInternalRestClient();
}
@Bean
public IngestInternalRestClientFactory ingestInternalRestClientFactory(final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties,
final RestTemplateBuilder restTemplateBuilder) {
return new IngestInternalRestClientFactory(apiIngestExternalApplicationProperties.getIngestInternalClient(), restTemplateBuilder);
public IngestInternalRestClientFactory ingestInternalRestClientFactory(
final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties,
final RestTemplateBuilder restTemplateBuilder) {
return new IngestInternalRestClientFactory(apiIngestExternalApplicationProperties.getIngestInternalClient(),
restTemplateBuilder);
}
@Bean
public IngestStreamingInternalRestClientFactory ingestStreamingInternalRestClientFactory(
final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties) {
return new IngestStreamingInternalRestClientFactory(
apiIngestExternalApplicationProperties.getIngestInternalClient());
}
@Bean
public IngestStreamingInternalRestClient ingestStreamingInternalRestClient(
final IngestStreamingInternalRestClientFactory factory) {
return factory.getIngestStreamingInternalRestClient();
}
@Bean
public IngestInternalRestClient ingestInternalRestClient(final IngestInternalRestClientFactory factory) {
......@@ -112,7 +150,8 @@ public class ApiIngestServerConfig extends AbstractContextConfiguration {
}
@Bean
public IngestInternalWebClientFactory ingestInternalWebClientFactory(final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties,
public IngestInternalWebClientFactory ingestInternalWebClientFactory(
final ApiIngestExternalApplicationProperties apiIngestExternalApplicationProperties,
final RestTemplateBuilder restTemplateBuilder) {
return new IngestInternalWebClientFactory(apiIngestExternalApplicationProperties.getIngestInternalClient());
}
......
......@@ -36,20 +36,19 @@
*/
package fr.gouv.vitamui.ingest.external.server.rest;
import fr.gouv.vitam.common.model.RequestResponseOK;
import fr.gouv.vitamui.common.security.SafeFileChecker;
import fr.gouv.vitamui.common.security.SanityChecker;
import fr.gouv.vitamui.commons.api.CommonConstants;
import fr.gouv.vitamui.commons.api.ParameterChecker;
import fr.gouv.vitamui.commons.api.domain.DirectionDto;
import fr.gouv.vitamui.commons.api.domain.PaginatedValuesDto;
import fr.gouv.vitamui.commons.api.domain.ServicesData;
import fr.gouv.vitamui.commons.api.exception.BadRequestException;
import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.commons.vitam.api.dto.LogbookOperationDto;
import fr.gouv.vitamui.ingest.common.rest.RestApi;
import fr.gouv.vitamui.ingest.external.server.service.IngestExternalService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
......@@ -62,17 +61,12 @@ 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 org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
/**
* UI Ingest External controller
*
*
*/
@Api(tags = "ingest")
@RequestMapping(RestApi.V1_INGEST)
......@@ -90,11 +84,14 @@ public class IngestExternalController {
}
@Secured(ServicesData.ROLE_GET_ALL_INGEST)
@GetMapping(params = { "page", "size" })
public PaginatedValuesDto<LogbookOperationDto> getAllPaginated(@RequestParam final Integer page, @RequestParam final Integer size,
@RequestParam(required = false) final Optional<String> criteria, @RequestParam(required = false) final Optional<String> orderBy,
@RequestParam(required = false) final Optional<DirectionDto> direction) {
LOGGER.debug("getPaginateEntities page={}, size={}, criteria={}, orderBy={}, ascendant={}", page, size, orderBy, direction);
@GetMapping(params = {"page", "size"})
public PaginatedValuesDto<LogbookOperationDto> getAllPaginated(@RequestParam final Integer page,
@RequestParam final Integer size,
@RequestParam(required = false) final Optional<String> criteria,
@RequestParam(required = false) final Optional<String> orderBy,
@RequestParam(required = false) final Optional<DirectionDto> direction) {
LOGGER.debug("getPaginateEntities page={}, size={}, criteria={}, orderBy={}, ascendant={}", page, size, orderBy,
direction);
return ingestExternalService.getAllPaginated(page, size, criteria, orderBy, direction);
}
......@@ -106,28 +103,6 @@ public class IngestExternalController {
return ingestExternalService.getOne(id);
}
@Secured(ServicesData.ROLE_CREATE_INGEST)
@PostMapping(value = CommonConstants.INGEST_UPLOAD, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<RequestResponseOK> upload(
@RequestHeader(value = CommonConstants.X_ACTION) final String action,
@RequestHeader(value = CommonConstants.X_CONTEXT_ID) final String contextId,
@RequestParam(CommonConstants.MULTIPART_FILE_PARAM_NAME) final MultipartFile file) {
ParameterChecker
.checkParameter("The Action and contextId are mandatory parameters : ", action, contextId);
SafeFileChecker.checkSafeFilePath(file.getOriginalFilename());
InputStream in = null;
try {
in = file.getInputStream();
LOGGER.debug("[IngestExternalController] upload file [{}], [{}] bytes.", file.getOriginalFilename(),
file.getInputStream().available());
} catch (IOException e) {
LOGGER.error("ERROR: InputStream error ", e);
throw new BadRequestException("ERROR: InputStream writing error : ", e);
}
return ingestExternalService.upload(in, action, contextId);
}
@Secured(ServicesData.ROLE_LOGBOOKS)
@GetMapping(RestApi.INGEST_REPORT_ODT + CommonConstants.PATH_ID)
public ResponseEntity<byte[]> generateODTReport(final @PathVariable("id") String id) {
......@@ -135,4 +110,19 @@ public class IngestExternalController {
ParameterChecker.checkParameter("The Identifier is a mandatory parameter :", id);
return ingestExternalService.generateODTReport(id);
}
@Secured(ServicesData.ROLE_CREATE_INGEST)
@ApiOperation(value = "Upload an streaming SIP", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@PostMapping(value = CommonConstants.INGEST_UPLOAD_V2, consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Void> streamingUpload(InputStream inputStream,
@RequestHeader(value = CommonConstants.X_ACTION) final String action,
@RequestHeader(value = CommonConstants.X_CONTEXT_ID) final String contextId,
@RequestHeader(value = CommonConstants.X_ORIGINAL_FILENAME_HEADER) final String originalFileName
) {
LOGGER.debug("[Internal] upload file v2: {}", originalFileName);
ParameterChecker.checkParameter("The action and the context ID are mandatory parameters: ", action, contextId,
originalFileName);
SanityChecker.isValidFileName(originalFileName);
return ingestExternalService.streamingUpload(inputStream, originalFileName, contextId, action);
}
}
......@@ -36,7 +36,6 @@
*/
package fr.gouv.vitamui.ingest.external.server.service;
import fr.gouv.vitam.common.model.RequestResponseOK;
import fr.gouv.vitamui.commons.api.ParameterChecker;
import fr.gouv.vitamui.commons.api.domain.DirectionDto;
import fr.gouv.vitamui.commons.api.domain.PaginatedValuesDto;
......@@ -45,13 +44,12 @@ import fr.gouv.vitamui.iam.security.client.AbstractResourceClientService;
import fr.gouv.vitamui.iam.security.service.ExternalSecurityService;
import fr.gouv.vitamui.ingest.internal.client.IngestInternalRestClient;
import fr.gouv.vitamui.ingest.internal.client.IngestInternalWebClient;
import fr.gouv.vitamui.ingest.internal.client.IngestStreamingInternalRestClient;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.io.InputStream;
import java.util.Optional;
......@@ -59,7 +57,6 @@ import java.util.stream.Collectors;
/**
* The service to create vitam ingest.
*
*/
@Getter
@Setter
......@@ -71,29 +68,31 @@ public class IngestExternalService extends AbstractResourceClientService<Logbook
@Autowired
private final IngestInternalWebClient ingestInternalWebClient;
@Autowired
private final IngestStreamingInternalRestClient ingestStreamingInternalRestClient;
public IngestExternalService(@Autowired IngestInternalRestClient ingestInternalRestClient,
IngestInternalWebClient ingestInternalWebClient,
final ExternalSecurityService externalSecurityService) {
final ExternalSecurityService externalSecurityService,
final IngestStreamingInternalRestClient ingestStreamingInternalRestClient) {
super(externalSecurityService);
this.ingestInternalRestClient = ingestInternalRestClient;
this.ingestInternalWebClient = ingestInternalWebClient;
this.ingestStreamingInternalRestClient = ingestStreamingInternalRestClient;
}
public Mono<RequestResponseOK> upload(InputStream in, String action, String contextId) {
return ingestInternalWebClient.upload(getInternalHttpContext(), in, action, contextId);
}
public PaginatedValuesDto<LogbookOperationDto> getAllPaginated(final Integer page, final Integer size, final Optional<String> criteria,
final Optional<String> orderBy, final Optional<DirectionDto> direction) {
public PaginatedValuesDto<LogbookOperationDto> getAllPaginated(final Integer page, final Integer size,
final Optional<String> criteria,
final Optional<String> orderBy, final Optional<DirectionDto> direction) {
ParameterChecker.checkPagination(size, page);
final PaginatedValuesDto<LogbookOperationDto> result = getClient().getAllPaginated(getInternalHttpContext(), page, size, criteria, orderBy, direction);
final PaginatedValuesDto<LogbookOperationDto> result =
getClient().getAllPaginated(getInternalHttpContext(), page, size, criteria, orderBy, direction);
return new PaginatedValuesDto<>(
result.getValues().stream().map(element -> converterToExternalDto(element)).collect(Collectors.toList()),
result.getPageNum(),
result.getPageSize(),
result.isHasMore());
result.getValues().stream().map(element -> converterToExternalDto(element)).collect(Collectors.toList()),
result.getPageNum(),
result.getPageSize(),
result.isHasMore());
}
public LogbookOperationDto getOne(final String id) {
......@@ -101,7 +100,7 @@ public class IngestExternalService extends AbstractResourceClientService<Logbook
}
public ResponseEntity<byte[]> generateODTReport(String id) {
public ResponseEntity<byte[]> generateODTReport(String id) {
return ingestInternalRestClient.generateODTReport(getInternalHttpContext(), id);
}
......@@ -109,4 +108,15 @@ public class IngestExternalService extends AbstractResourceClientService<Logbook
protected IngestInternalRestClient getClient() {
return ingestInternalRestClient;
}
public ResponseEntity<Void> streamingUpload(InputStream inputStream, final String originalFileName,
final String contextId,
final String action) {
return
ingestStreamingInternalRestClient
.streamingUpload(getInternalHttpContext(), originalFileName, inputStream, contextId,
action);
}
}
......@@ -58,7 +58,8 @@ import java.util.List;
/**
* Ingest Internal REST Client.
*/
public class IngestInternalRestClient extends BasePaginatingAndSortingRestClient<LogbookOperationDto, InternalHttpContext> {
public class IngestInternalRestClient
extends BasePaginatingAndSortingRestClient<LogbookOperationDto, InternalHttpContext> {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(IngestInternalRestClient.class);
......@@ -71,20 +72,26 @@ public class IngestInternalRestClient extends BasePaginatingAndSortingRestClient
return RestApi.V1_INGEST;
}
@Override protected Class<LogbookOperationDto> getDtoClass() {
@Override
protected Class<LogbookOperationDto> getDtoClass() {
return LogbookOperationDto.class;
}
@Override protected ParameterizedTypeReference<List<LogbookOperationDto>> getDtoListClass() {
return new ParameterizedTypeReference<List<LogbookOperationDto>>() {};
@Override
protected ParameterizedTypeReference<List<LogbookOperationDto>> getDtoListClass() {
return new ParameterizedTypeReference<List<LogbookOperationDto>>() {
};
}
@Override protected ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>> getDtoPaginatedClass() {
return new ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>>() {};
@Override
protected ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>> getDtoPaginatedClass() {
return new ParameterizedTypeReference<PaginatedValuesDto<LogbookOperationDto>>() {
};
}
public ResponseEntity<byte[]> generateODTReport(InternalHttpContext context , String id) {
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.INGEST_REPORT_ODT + CommonConstants.PATH_ID );
public ResponseEntity<byte[]> generateODTReport(InternalHttpContext context, String id) {
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.INGEST_REPORT_ODT + CommonConstants.PATH_ID);
final HttpEntity<AuditOptions> request = new HttpEntity<>(buildHeaders(context));
return restTemplate.exchange(uriBuilder.build(id), HttpMethod.GET, request, byte[].class);
}
......
......@@ -43,18 +43,18 @@ import org.springframework.boot.web.client.RestTemplateBuilder;
/**
* A Rest client factory to create specialized IAM Rest clients
*
*
*/
public class IngestInternalRestClientFactory extends BaseRestClientFactory {
public IngestInternalRestClientFactory(final RestClientConfiguration restClientConfiguration, final RestTemplateBuilder restTemplateBuilder) {
public IngestInternalRestClientFactory(final RestClientConfiguration restClientConfiguration,
final RestTemplateBuilder restTemplateBuilder) {
super(restClientConfiguration, restTemplateBuilder);
}
public IngestInternalRestClientFactory(final RestClientConfiguration restClientConfiguration, final HttpPoolConfiguration httpHostConfiguration,
final RestTemplateBuilder restTemplateBuilder) {
public IngestInternalRestClientFactory(final RestClientConfiguration restClientConfiguration,
final HttpPoolConfiguration httpHostConfiguration,
final RestTemplateBuilder restTemplateBuilder) {
super(restClientConfiguration, httpHostConfiguration, restTemplateBuilder);
}
......
......@@ -36,29 +36,12 @@
*/
package fr.gouv.vitamui.ingest.internal.client;
import fr.gouv.vitam.common.model.RequestResponseOK;
import fr.gouv.vitamui.commons.api.CommonConstants;
import fr.gouv.vitamui.commons.api.exception.BadRequestException;
import fr.gouv.vitamui.commons.api.exception.FileOperationException;
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 fr.gouv.vitamui.ingest.common.rest.RestApi;
import org.springframework.http.HttpMethod;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.AbstractMap;
import java.util.Optional;
/**
* External WebClient for Ingest operations.
......@@ -71,35 +54,6 @@ public class IngestInternalWebClient extends BaseWebClient<InternalHttpContext>
super(webClient, baseUrl);
}
public Mono<RequestResponseOK> upload(final InternalHttpContext context, InputStream in, final String action,
final String contextId) {
if (in == null) {
throw new FileOperationException("There is an error in uploaded file !");
}
final Path tmpFilePath =
Paths.get(System.getProperty(CommonConstants.VITAMUI_TEMP_DIRECTORY), context.getRequestId());
int length = 0;
try {
length = in.available();
Files.copy(in, tmpFilePath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
LOGGER.debug("[IngestInternalWebClient] Error writing InputStream of length [{}] to temporary path {}",
length, tmpFilePath.toAbsolutePath());
throw new BadRequestException("ERROR: InputStream writing error : ", e);
}
final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(CommonConstants.X_CONTEXT_ID, contextId);
headers.add(CommonConstants.X_ACTION, action);
return multipartDataFromFile(getPathUrl() + CommonConstants.INGEST_UPLOAD, HttpMethod.POST, context,
Optional.of(new AbstractMap.SimpleEntry<>(CommonConstants.MULTIPART_FILE_PARAM_NAME, tmpFilePath)),
headers)
.bodyToMono(RequestResponseOK.class);
}
@Override
public String getPathUrl() {
return RestApi.V1_INGEST;
......
/**
* 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.ingest.internal.client;
import fr.gouv.vitam.common.model.AuditOptions;
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.InternalHttpContext;
import fr.gouv.vitamui.commons.vitam.api.dto.LogbookOperationDto;
import fr.gouv.vitamui.ingest.common.rest.RestApi;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.InputStream;
import java.util.List;
/**
* Ingest Streaming Internal REST Client.
*/
public class IngestStreamingInternalRestClient
extends BasePaginatingAndSortingRestClient<LogbookOperationDto, InternalHttpContext> {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(IngestStreamingInternalRestClient.class);
public IngestStreamingInternalRestClient(final RestTemplate restTemplate, final String baseUrl) {
super(restTemplate, baseUrl);
}
@Override
public String getPathUrl() {
return RestApi.V1_INGEST;
}
@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<Void> streamingUpload(final InternalHttpContext context, String originalFileName,
InputStream inputStream,
final String contextId,
final String action) {
LOGGER.debug("Calling upload using streaming process");
final UriComponentsBuilder uriBuilder =
UriComponentsBuilder.fromHttpUrl(getUrl() + RestApi.INGEST_UPLOAD_V2);
final MultiValueMap<String, String> headersList = new HttpHeaders();
headersList.addAll(buildHeaders(context));
headersList.add(CommonConstants.X_CONTEXT_ID, contextId);
headersList.add(CommonConstants.X_ACTION, action);
headersList.add(CommonConstants.X_ORIGINAL_FILENAME_HEADER, originalFileName);
HttpHeaders headersParams = new HttpHeaders();
headersParams.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headersParams.addAll(headersList);
final HttpEntity<InputStreamResource> request =
new HttpEntity<>(new InputStreamResource(inputStream), headersParams);
final ResponseEntity<Void> response =
restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.POST,
request, Void.class);
LOGGER.info("The response on ingest is {} ", response.toString());
return response;
}
}
/**
* 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.ingest.internal.client;
import fr.gouv.vitamui.commons.rest.client.BaseRestClientFactory;
import fr.gouv.vitamui.commons.rest.client.BaseStreamingRestClientFactory;
import fr.gouv.vitamui.commons.rest.client.configuration.HttpPoolConfiguration;
import fr.gouv.vitamui.commons.rest.client.configuration.RestClientConfiguration;
import org.springframework.boot.web.client.RestTemplateBuilder;
/**
* A Rest client factory to create specialized IAM Rest clients
*
*
*/
public class IngestStreamingInternalRestClientFactory extends BaseStreamingRestClientFactory {
public IngestStreamingInternalRestClientFactory(final RestClientConfiguration restClientConfiguration) {
super(restClientConfiguration);
}
public IngestStreamingInternalRestClientFactory(final RestClientConfiguration restClientConfiguration, final HttpPoolConfiguration httpHostConfiguration) {
super(restClientConfiguration, httpHostConfiguration);
}
public IngestStreamingInternalRestClient getIngestStreamingInternalRestClient() {
return new IngestStreamingInternalRestClient(getRestTemplate(), getBaseUrl());
}
}
......@@ -15,12 +15,6 @@ spring:
mongodb:
uri: mongodb://mongod_dbuser_iam:mongod_dbpwd_iam@localhost:27018/iam?connectTimeoutMS=2000
multipart:
enabled: true
spring.servlet.multipart.max-file-size: -1
spring.servlet.multipart.max-request-size: -1
server-identity:
identityName: vitamui-dev
identityRole: ingest-internal
......
......@@ -36,6 +36,7 @@
*/
package fr.gouv.vitamui.ingest.internal.server.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.gouv.vitam.ingest.external.client.IngestExternalClient;
import fr.gouv.vitamui.commons.api.application.AbstractContextConfiguration;
import fr.gouv.vitamui.commons.mongo.config.MongoConfig;
......@@ -61,11 +62,14 @@ import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
@Configuration
@Import({RestExceptionHandler.class, MongoConfig.class, SwaggerConfiguration.class, WebSecurityConfig.class, VitamAccessConfig.class, VitamIngestConfig.class,
@Import({RestExceptionHandler.class, MongoConfig.class, SwaggerConfiguration.class, WebSecurityConfig.class,
VitamAccessConfig.class, VitamIngestConfig.class,
VitamAdministrationConfig.class})
public class ApiIngestInternalServerConfig extends AbstractContextConfiguration {
......@@ -83,17 +87,31 @@ public class ApiIngestInternalServerConfig extends AbstractContextConfiguration
}
@Bean
public InternalApiAuthenticationProvider internalApiAuthenticationProvider(final InternalAuthentificationService internalAuthentificationService) {
public MappingJackson2HttpMessageConverter customizedJacksonMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(
Arrays.asList(
MediaType.APPLICATION_JSON,
new MediaType("application", "*+json"),
MediaType.APPLICATION_OCTET_STREAM));
return converter;
}
@Bean
public InternalApiAuthenticationProvider internalApiAuthenticationProvider(
final InternalAuthentificationService internalAuthentificationService) {
return new InternalApiAuthenticationProvider(internalAuthentificationService);
}
@Bean
public UserInternalRestClient userInternalRestClient(final IamInternalRestClientFactory iamInternalRestClientFactory) {
public UserInternalRestClient userInternalRestClient(
final IamInternalRestClientFactory iamInternalRestClientFactory) {
return iamInternalRestClientFactory.getUserInternalRestClient();
}
@Bean
public InternalAuthentificationService internalAuthentificationService(final UserInternalRestClient userInternalRestClient) {
public InternalAuthentificationService internalAuthentificationService(
final UserInternalRestClient userInternalRestClient) {
return new InternalAuthentificationService(userInternalRestClient);
}
......@@ -101,8 +119,10 @@ public class ApiIngestInternalServerConfig extends AbstractContextConfiguration
public InternalSecurityService securityService() {
return new InternalSecurityService();
}
@Bean
public CustomerInternalRestClient customerInternalRestClient(final IamInternalRestClientFactory iamInternalRestClientFactory) {
public CustomerInternalRestClient customerInternalRestClient(
final IamInternalRestClientFactory iamInternalRestClientFactory) {
return iamInternalRestClientFactory.getCustomerInternalRestClient();
}
......@@ -113,14 +133,15 @@ public class ApiIngestInternalServerConfig extends AbstractContextConfiguration
@Bean
public IngestInternalService ingestInternalService(
final InternalSecurityService internalSecurityService,
final LogbookService logbookService,
final ObjectMapper objectMapper,
final IngestExternalClient ingestExternalClient,
final IngestService ingestService,
final CustomerInternalRestClient customerInternalRestClient,
final IngestGeneratorODTFile ingestGeneratorODTFile) {
return new IngestInternalService(internalSecurityService, logbookService, objectMapper, ingestExternalClient, ingestService,
final InternalSecurityService internalSecurityService,
final LogbookService logbookService,
final ObjectMapper objectMapper,
final IngestExternalClient ingestExternalClient,
final IngestService ingestService,
final CustomerInternalRestClient customerInternalRestClient,
final IngestGeneratorODTFile ingestGeneratorODTFile) {
return new IngestInternalService(internalSecurityService, logbookService, objectMapper, ingestExternalClient,
ingestService,
customerInternalRestClient, ingestGeneratorODTFile);
}
}
......@@ -27,7 +27,6 @@
package fr.gouv.vitamui.ingest.internal.server.rest;
import fr.gouv.vitam.common.client.VitamContext;
import fr.gouv.vitam.common.model.RequestResponseOK;
import fr.gouv.vitam.ingest.external.api.exception.IngestExternalException;
import fr.gouv.vitamui.common.security.SanityChecker;
import fr.gouv.vitamui.commons.api.CommonConstants;
......@@ -37,15 +36,14 @@ import fr.gouv.vitamui.commons.api.domain.PaginatedValuesDto;
import fr.gouv.vitamui.commons.api.exception.IngestFileGenerationException;
import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.iam.security.service.InternalSecurityService;
import fr.gouv.vitamui.commons.vitam.api.dto.LogbookOperationDto;
import fr.gouv.vitamui.iam.security.service.InternalSecurityService;
import fr.gouv.vitamui.ingest.common.rest.RestApi;
import fr.gouv.vitamui.ingest.internal.server.service.IngestInternalService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
......@@ -57,9 +55,9 @@ import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Optional;
......@@ -77,16 +75,21 @@ public class IngestInternalController {
private InternalSecurityService securityService;
@Autowired
public IngestInternalController(final IngestInternalService ingestInternalService, final InternalSecurityService securityService) {
public IngestInternalController(final IngestInternalService ingestInternalService,
final InternalSecurityService securityService) {
this.ingestInternalService = ingestInternalService;
this.securityService = securityService;
}
@GetMapping(params = {"page", "size"})
public PaginatedValuesDto<LogbookOperationDto> getAllPaginated(@RequestParam final Integer page, @RequestParam final Integer size,
@RequestParam(required = false) final Optional<String> criteria, @RequestParam(required = false) final Optional<String> orderBy,
@RequestParam(required = false) final Optional<DirectionDto> direction) {
LOGGER.debug("getPaginateEntities page={}, size={}, criteria={}, orderBy={}, ascendant={}", page, size, criteria, orderBy, direction);
public PaginatedValuesDto<LogbookOperationDto> getAllPaginated(@RequestParam final Integer page,
@RequestParam final Integer size,
@RequestParam(required = false) final Optional<String> criteria,
@RequestParam(required = false) final Optional<String> orderBy,
@RequestParam(required = false) final Optional<DirectionDto> direction) {
LOGGER
.debug("getPaginateEntities page={}, size={}, criteria={}, orderBy={}, ascendant={}", page, size, criteria,
orderBy, direction);
final VitamContext vitamContext = securityService.buildVitamContext(securityService.getTenantIdentifier());
return ingestInternalService.getAllPaginated(page, size, orderBy, direction, vitamContext, criteria);
}
......@@ -99,31 +102,34 @@ public class IngestInternalController {
return ingestInternalService.getOne(vitamContext, id);
}
@PostMapping(value = CommonConstants.INGEST_UPLOAD, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public RequestResponseOK upload(
@RequestHeader(value = CommonConstants.X_ACTION) final String action,
@RequestHeader(value = CommonConstants.X_CONTEXT_ID) final String contextId,
@RequestParam(CommonConstants.MULTIPART_FILE_PARAM_NAME) final MultipartFile path)
throws IngestExternalException {
LOGGER.debug("[Internal] upload file : {}", path.getOriginalFilename());
ParameterChecker.checkParameter("The action and the context ID are mandatory parameters: ", action, contextId);
SanityChecker.isValidFileName(path.getOriginalFilename());
return ingestInternalService.upload(path, contextId, action);
}
@GetMapping(RestApi.INGEST_REPORT_ODT + CommonConstants.PATH_ID)
public ResponseEntity<byte[]> generateODTReport(final @PathVariable("id") String id)
throws IngestFileGenerationException {
final VitamContext vitamContext = securityService.buildVitamContext(securityService.getTenantIdentifier());
try {
LOGGER.debug("export ODT report for operation with id :{}", id);
ParameterChecker.checkParameter("Identifier is mandatory : ", id);
byte[] response = this.ingestInternalService.generateODTReport(vitamContext, id);
return new ResponseEntity<>(response, HttpStatus.OK);
}
catch(IOException | URISyntaxException | IngestFileGenerationException e) {
LOGGER.error("Error with generating Report : {} " , e.getMessage());
try {
LOGGER.debug("export ODT report for operation with id :{}", id);
ParameterChecker.checkParameter("Identifier is mandatory : ", id);
byte[] response = this.ingestInternalService.generateODTReport(vitamContext, id);
return new ResponseEntity<>(response, HttpStatus.OK);
} catch (IOException | URISyntaxException | IngestFileGenerationException e) {
LOGGER.error("Error with generating Report : {} ", e.getMessage());
throw new IngestFileGenerationException("Unable to generate the ingest report " + e);
}
}
}
@ApiOperation(value = "Upload an SIP", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@PostMapping(value = CommonConstants.INGEST_UPLOAD_V2, consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void streamingUpload(
InputStream inputStream,
@RequestHeader(value = CommonConstants.X_ACTION) final String action,
@RequestHeader(value = CommonConstants.X_CONTEXT_ID) final String contextId,
@RequestHeader(value = CommonConstants.X_ORIGINAL_FILENAME_HEADER) final String originalFileName
)
throws IngestExternalException {
LOGGER.debug("[Internal] upload file v2: {}", originalFileName);
ParameterChecker.checkParameter("The action and the context ID are mandatory parameters: ", action, contextId,
originalFileName);
SanityChecker.isValidFileName(originalFileName);
ingestInternalService.streamingUpload(inputStream, contextId, action);
}
}
......@@ -57,7 +57,6 @@ import fr.gouv.vitamui.iam.security.service.InternalSecurityService;
import fr.gouv.vitamui.ingest.common.dsl.VitamQueryHelper;
import fr.gouv.vitamui.ingest.common.dto.ArchiveUnitDto;
import fr.gouv.vitamui.ingest.internal.server.rest.IngestInternalController;
import org.odftoolkit.simple.TextDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
......@@ -65,8 +64,8 @@ import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;
import java.io.ByteArrayOutputStream;
import javax.ws.rs.core.Response;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
......@@ -77,8 +76,6 @@ import java.util.Optional;
/**
* Ingest Internal service communication with VITAM.
*
*
*/
public class IngestInternalService {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(IngestInternalController.class);
......@@ -103,8 +100,7 @@ public class IngestInternalService {
final LogbookService logbookService, final ObjectMapper objectMapper,
final IngestExternalClient ingestExternalClient, final IngestService ingestService,
final CustomerInternalRestClient customerInternalRestClient,
final IngestGeneratorODTFile ingestGeneratorODTFile)
{
final IngestGeneratorODTFile ingestGeneratorODTFile) {
this.internalSecurityService = internalSecurityService;
this.ingestExternalClient = ingestExternalClient;
this.logbookService = logbookService;
......@@ -123,14 +119,13 @@ public class IngestInternalService {
RequestResponse<Void> ingestResponse = null;
try {
LOGGER.info("Upload EvIdAppSession : {} " , vitamContext.getApplicationSessionId());
LOGGER.info("Upload EvIdAppSession : {} ", vitamContext.getApplicationSessionId());
ingestResponse = ingestService.ingest(vitamContext, path.getInputStream(), contextId, action);
LOGGER.info("The recieved stream size : " + path.getInputStream().available() + " is sent to Vitam");
if(ingestResponse.isOk()) {
if (ingestResponse.isOk()) {
LOGGER.debug("Ingest passed successfully : " + ingestResponse.toString());
}
else {
} else {
LOGGER.debug("Ingest failed with status : " + ingestResponse.getHttpCode());
}
} catch (IOException | IngestExternalException e) {
......@@ -148,7 +143,7 @@ public class IngestInternalService {
Map<String, Object> vitamCriteria = new HashMap<>();
JsonNode query;
try {
LOGGER.info(" All ingests EvIdAppSession : {} " , vitamContext.getApplicationSessionId());
LOGGER.info(" All ingests EvIdAppSession : {} ", vitamContext.getApplicationSessionId());
if (criteria.isPresent()) {
TypeReference<HashMap<String, Object>> typRef = new TypeReference<HashMap<String, Object>>() {
};
......@@ -173,13 +168,14 @@ public class IngestInternalService {
final RequestResponse<LogbookOperation> requestResponse;
try {
LOGGER.info("Ingest EvIdAppSession : {} " , vitamContext.getApplicationSessionId());
LOGGER.info("Ingest EvIdAppSession : {} ", vitamContext.getApplicationSessionId());
requestResponse = logbookService.selectOperationbyId(id, vitamContext);
LOGGER.debug("One Ingest Response: {}: ", requestResponse);
final LogbookOperationsResponseDto logbookOperationDtos = objectMapper.treeToValue(requestResponse.toJsonNode(), LogbookOperationsResponseDto.class);
final LogbookOperationsResponseDto logbookOperationDtos =
objectMapper.treeToValue(requestResponse.toJsonNode(), LogbookOperationsResponseDto.class);
List<LogbookOperationDto> singleLogbookOperationDto =
IngestConverter.convertVitamsToDtos(logbookOperationDtos.getResults());
......@@ -194,7 +190,7 @@ public class IngestInternalService {
private LogbookOperationsResponseDto findAll(VitamContext vitamContext, JsonNode query) {
final RequestResponse<LogbookOperation> requestResponse;
try {
LOGGER.info("All Ingest EvIdAppSession : {} " , vitamContext.getApplicationSessionId());
LOGGER.info("All Ingest EvIdAppSession : {} ", vitamContext.getApplicationSessionId());
requestResponse = logbookService.selectOperations(query, vitamContext);
LOGGER.debug("Response: {}: ", requestResponse);
......@@ -256,29 +252,32 @@ public class IngestInternalService {
try {
Document atr = ingestGeneratorODTFile.convertStringToXMLDocument(getAtrAsString(vitamContext, id));
Document manifest = ingestGeneratorODTFile.convertStringToXMLDocument(getManifestAsString(vitamContext, id));
Document manifest =
ingestGeneratorODTFile.convertStringToXMLDocument(getManifestAsString(vitamContext, id));
TextDocument document;
try {
document = TextDocument.newTextDocument();
} catch (Exception e) {
LOGGER.error("Error to initialize the document : {} " , e.getMessage());
throw new IngestFileGenerationException("Error to initialize the document : {} " , e);
LOGGER.error("Error to initialize the document : {} ", e.getMessage());
throw new IngestFileGenerationException("Error to initialize the document : {} ", e);
}
if(myCustomer.isHasCustomGraphicIdentity()) {
customerLogo = customerInternalRestClient.getLogo(internalSecurityService.getHttpContext(), myCustomer.getId(), AttachmentType.HEADER).getBody();
if (myCustomer.isHasCustomGraphicIdentity()) {
customerLogo = customerInternalRestClient
.getLogo(internalSecurityService.getHttpContext(), myCustomer.getId(), AttachmentType.HEADER)
.getBody();
}
List<ArchiveUnitDto> archiveUnitDtoList = ingestGeneratorODTFile.getValuesForDynamicTable(atr,manifest);
List<ArchiveUnitDto> archiveUnitDtoList = ingestGeneratorODTFile.getValuesForDynamicTable(atr, manifest);
ingestGeneratorODTFile.generateDocumentHeader(document,myCustomer,customerLogo);
ingestGeneratorODTFile.generateDocumentHeader(document, myCustomer, customerLogo);
ingestGeneratorODTFile.generateFirstTitle(document);
ingestGeneratorODTFile.generateServicesTable(document,manifest);
ingestGeneratorODTFile.generateServicesTable(document, manifest);
ingestGeneratorODTFile.generateDepositDataTable(document,manifest,archiveUnitDtoList);
ingestGeneratorODTFile.generateDepositDataTable(document, manifest, archiveUnitDtoList);
ingestGeneratorODTFile.generateOperationDataTable(document,manifest,id);
ingestGeneratorODTFile.generateOperationDataTable(document, manifest, id);
ingestGeneratorODTFile.generateResponsibleSignatureTable(document);
......@@ -286,24 +285,44 @@ public class IngestInternalService {
ingestGeneratorODTFile.generateSecondtTitle(document);
ingestGeneratorODTFile.generateArchiveUnitDetailsTable(document,archiveUnitDtoList);
ingestGeneratorODTFile.generateArchiveUnitDetailsTable(document, archiveUnitDtoList);
LOGGER.info("Generate ODT Report EvIdAppSession : {} " , vitamContext.getApplicationSessionId());
LOGGER.info("Generate ODT Report EvIdAppSession : {} ", vitamContext.getApplicationSessionId());
ByteArrayOutputStream result = new ByteArrayOutputStream();
try {
document.save(result);
} catch (Exception e) {
LOGGER.error("Error to save the document : {} " , e.getMessage());
throw new IngestFileGenerationException("Error to save the document : {} " , e);
LOGGER.error("Error to save the document : {} ", e.getMessage());
throw new IngestFileGenerationException("Error to save the document : {} ", e);
}
return result.toByteArray();
} catch (IOException | URISyntaxException | IngestFileGenerationException e) {
LOGGER.error("Error with generating Report : {} " , e.getMessage());
throw new IngestFileGenerationException("Unable to generate the ingest report ", e) ;
LOGGER.error("Error with generating Report : {} ", e.getMessage());
throw new IngestFileGenerationException("Unable to generate the ingest report ", e);
}
}
public void streamingUpload(InputStream inputStream, String contextId, String action)
throws IngestExternalException {
RequestResponse<Void> ingestResponse;
try {
final VitamContext vitamContext =
internalSecurityService.buildVitamContext(internalSecurityService.getTenantIdentifier());
ingestResponse =
ingestExternalClient.ingest(vitamContext, inputStream, contextId, action);
if (ingestResponse.isOk()) {
LOGGER.debug("Ingest passed successfully : " + ingestResponse.toString());
} else {
LOGGER.debug("Ingest failed with status : " + ingestResponse.getHttpCode());
}
} catch (Exception e) {
LOGGER.debug("Error sending upload to vitam ", e);
throw new IngestExternalException(e);
}
}
}
......@@ -313,6 +313,7 @@ public class CommonConstants {
public static final String MULTIPART_FILE_PARAM_NAME = "uploadedFile";
public static final String INGEST_UPLOAD = "/upload";
public static final String INGEST_UPLOAD_V2 = "/upload-v2";
public static final String X_ACTION = "X-Action";
public static final String X_CONTEXT_ID = "X-Context-Id";
public static final String X_SIZE_TOTAL = "X-Size-Total";
......
/**
* 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.commons.rest.client;
import fr.gouv.vitamui.commons.api.exception.ApplicationServerException;
import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.commons.rest.client.configuration.HttpPoolConfiguration;
import fr.gouv.vitamui.commons.rest.client.configuration.RestClientConfiguration;
import fr.gouv.vitamui.commons.rest.client.configuration.SSLConfiguration;
import fr.gouv.vitamui.commons.rest.util.RestUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.UUID;
/**
* A rest client factory to create each domain specific REST client. The http connection is configured by the
* RestClientConfiguration object. The factory implements a connection pool configured by the HttpPoolConfiguration
* object and handles SSL via x509 certificates.
*
*
*/
public class BaseStreamingRestClientFactory implements RestClientFactory {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(BaseStreamingRestClientFactory.class);
private final RestTemplate restTemplate;
private final String baseUrl;
protected int connectTimeout = 500000;
protected int connectionRequestTimeout = 500000;
protected int socketTimeout = 500000;
public BaseStreamingRestClientFactory(final RestClientConfiguration restClientConfiguration) {
this(restClientConfiguration, null);
}
public BaseStreamingRestClientFactory(final RestClientConfiguration restClientConfig, final HttpPoolConfiguration httpPoolConfig) {
Assert.notNull(restClientConfig, "Rest client configuration must be specified");
final boolean useSSL = restClientConfig.isSecure();
baseUrl = RestUtils.getScheme(useSSL) + restClientConfig.getServerHost() + ":" + restClientConfig.getServerPort();
HttpPoolConfiguration myPoolConfig = httpPoolConfig;
// configure the pool from the restClientConfig if the value of poolMaxTotal is positive
if(restClientConfig.getPoolMaxTotal() >= 0) {
myPoolConfig = new HttpPoolConfiguration();
myPoolConfig.setMaxTotal(restClientConfig.getPoolMaxTotal());
myPoolConfig.setMaxPerRoute(restClientConfig.getPoolMaxPerRoute());
}
final Registry<ConnectionSocketFactory> csfRegistry = useSSL ? buildRegistry(restClientConfig.getSslConfiguration()) : null;
final PoolingHttpClientConnectionManager connectionManager = buildConnectionManager(myPoolConfig, csfRegistry);
final RequestConfig requestConfig = buildRequestConfig();
final CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
requestFactory.setBufferRequestBody(false);
restTemplate = new RestTemplate(requestFactory);
restTemplate.setErrorHandler(new ErrorHandler());
}
/*
* Create an SSLContext that uses client.p12 as the client certificate
* and the truststore.jks as the trust material (trusted CA certificates).
* Then create SSLConnectionSocketFactory to register with the HTTPS protocol.
*/
private Registry<ConnectionSocketFactory> buildRegistry(final SSLConfiguration sslConfiguration) {
if (sslConfiguration == null) {
throw new ApplicationServerException("SSL Configuration is not defined. Unable to configure the SSLConnection");
}
final SSLConfiguration.CertificateStoreConfiguration ks = sslConfiguration.getKeystore();
final SSLConfiguration.CertificateStoreConfiguration ts = sslConfiguration.getTruststore();
SSLContext sslContext = null;
try {
final SSLContextBuilder sslContextBuilder = SSLContextBuilder.create();
if (ks != null) {
final KeyStore keyStore = loadPkcs(ks.getType(), ks.getKeyPath(), ks.getKeyPassword().toCharArray());
sslContextBuilder.loadKeyMaterial(keyStore, ks.getKeyPassword().toCharArray());
}
sslContext = sslContextBuilder.loadTrustMaterial(new File(ts.getKeyPath()), ts.getKeyPassword().toCharArray()).setProtocol("TLS")
.setSecureRandom(new java.security.SecureRandom()).build();
}
catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | CertificateException | IOException | UnrecoverableKeyException e) {
LOGGER.error("Unable to build the Registry<ConnectionSocketFactory>.", e);
LOGGER.error("KeyPath: " + sslConfiguration.getKeystore().getKeyPath());
throw new ApplicationServerException(e);
}
final HostnameVerifier hostnameVerifier = sslConfiguration.isHostnameVerification() ? null : TrustAllHostnameVerifier.INSTANCE;
final SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
return RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslFactory).build();
}
private KeyStore loadPkcs(final String type, final String filename, final char[] password)
throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
final KeyStore keyStore = KeyStore.getInstance(type);
final File key = ResourceUtils.getFile(filename);
try (InputStream in = new FileInputStream(key)) {
keyStore.load(in, password);
}
return keyStore;
}
/*
* Create a ClientConnectionPoolManager that maintains a pool of HttpClientConnections and is able to service connection
* requests from multiple execution threads. Connections are pooled on a per route basis. A request for a route which
* already the manager has persistent connections for available in the pool will be services by leasing a connection
* from the pool rather than creating a brand new connection.
*/
private PoolingHttpClientConnectionManager buildConnectionManager(final HttpPoolConfiguration poolConfig,
final Registry<ConnectionSocketFactory> socketFactoryRegistry) {
final PoolingHttpClientConnectionManager connectionManager = (socketFactoryRegistry != null)
? new PoolingHttpClientConnectionManager(socketFactoryRegistry)
: new PoolingHttpClientConnectionManager();
if (poolConfig != null) {
connectionManager.setMaxTotal(poolConfig.getMaxTotal());
// Default max per route is used in case it's not set for a specific route
connectionManager.setDefaultMaxPerRoute(poolConfig.getMaxPerRoute());
for (final HttpPoolConfiguration.HostConfiguration hostConfig : poolConfig.getHostConfigurations()) {
final HttpHost host = new HttpHost(hostConfig.getHost(), hostConfig.getPort(), hostConfig.getScheme());
// Max per route for a specific hosts route
connectionManager.setMaxPerRoute(new HttpRoute(host), hostConfig.getMaxPerRoute());
}
}
return connectionManager;
}
private RequestConfig buildRequestConfig() {
return RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout).setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout)
.build();
}
@Override
public RestTemplate getRestTemplate() {
return restTemplate;
}
@Override
public String getBaseUrl() {
return baseUrl;
}
public void setRestClientInterceptor(final List<ClientHttpRequestInterceptor> interceptors) {
restTemplate.setInterceptors(interceptors);
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment