diff --git a/openapi/openapi.json b/openapi/openapi.json index 0967ef42..1fe9e452 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -1 +1,141 @@ -{} +{ + "openapi" : "3.0.1", + "info" : { + "description" : "A service that permits to handle nodoInviaRPT and nodoInviaCarrelloRPT request from WISP, interfacing them with GPD system", + "termsOfService" : "https://www.pagopa.gov.it/", + "title" : "wisp-converter", + "version" : "0.0.0" + }, + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/info" : { + "get" : { + "operationId" : "healthCheck", + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/AppInfo" + } + } + }, + "description" : "OK.", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" + } + } + } + }, + "401" : { + "description" : "Wrong or missing function key.", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" + } + } + } + }, + "403" : { + "description" : "Forbidden.", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" + } + } + } + }, + "500" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ProblemJson" + } + } + }, + "description" : "Service unavailable.", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" + } + } + } + } + }, + "security" : [ { + "ApiKey" : [ ] + } ], + "summary" : "Return OK if application is started", + "tags" : [ "Home" ] + }, + "parameters" : [ { + "description" : "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.", + "in" : "header", + "name" : "X-Request-Id", + "schema" : { + "type" : "string" + } + } ] + } + }, + "components" : { + "schemas" : { + "AppInfo" : { + "type" : "object", + "properties" : { + "environment" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "version" : { + "type" : "string" + } + } + }, + "ProblemJson" : { + "type" : "object", + "properties" : { + "detail" : { + "type" : "string", + "description" : "A human readable explanation specific to this occurrence of the problem.", + "example" : "There was an error processing the request" + }, + "status" : { + "maximum" : 600, + "minimum" : 100, + "type" : "integer", + "description" : "The HTTP status code generated by the origin server for this occurrence of the problem.", + "format" : "int32", + "example" : 200 + }, + "title" : { + "type" : "string", + "description" : "A short, summary of the problem type. Written in english and readable for engineers (usually not suited for non technical stakeholders and not localized); example: Service Unavailable" + } + } + } + }, + "securitySchemes" : { + "ApiKey" : { + "description" : "The API key to access this function app.", + "in" : "header", + "name" : "Ocp-Apim-Subscription-Key", + "type" : "apiKey" + } + } + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index bf2ffc26..e3949e92 100644 --- a/pom.xml +++ b/pom.xml @@ -7,22 +7,24 @@ org.springframework.boot spring-boot-starter-parent - 2.7.3 + 3.2.3 + it.gov.pagopa wisp-converter 0.0.0 pagoPA WISP Converter - A service that permits to handle nodoInviaRPT and nodoInviaCarrelloRPT request from WISP, interfacing - them with GPD system - + A service that permits to handle nodoInviaRPT and nodoInviaCarrelloRPT request from WISP, interfacing them with GPD system - 17 - 17 - UTF-8 - 1.6.15 + 17 + 1.5.5.Final + 2.4.0 + 1.6.0 + 1.9.20.1 + 1.2.21 + 4.1.101.Final @@ -36,81 +38,71 @@ org.springframework.boot - spring-boot-starter-web-services + spring-boot-starter-actuator org.springframework.boot - spring-boot-starter-data-redis + spring-boot-starter-aop - + + + + org.springframework.boot - spring-boot-devtools - runtime - true + spring-boot-starter-web-services org.springframework.boot - spring-boot-configuration-processor - true + spring-boot-starter-data-redis org.springframework.boot - spring-boot-starter-test - test + spring-boot-starter-cache - org.springframework.boot - spring-boot-starter-actuator + com.github.ben-manes.caffeine + caffeine + + org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.data - spring-data-jpa + spring-boot-devtools + runtime + true org.springframework.boot - spring-boot-starter-cache + spring-boot-configuration-processor + true - com.github.ben-manes.caffeine - caffeine + org.springframework.boot + spring-boot-starter-test + test + org.springdoc - springdoc-openapi-ui - ${springdoc.version} - - - - org.hibernate.orm - hibernate-core - 6.1.3.Final - - - - org.springframework.cloud - spring-cloud-starter-openfeign - 4.0.3 + springdoc-openapi-starter-webmvc-ui + ${springdoc-openapi-starter-webmvc-ui} - - org.modelmapper - modelmapper - 3.1.0 - org.projectlombok lombok true + + org.mapstruct + mapstruct + ${mapstruct.version} + junit @@ -120,7 +112,7 @@ co.elastic.logging logback-ecs-encoder - 1.5.0 + ${java-ecs-logging.version} @@ -145,13 +137,53 @@ + + no-sonar + + true + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + ${java.version} + ${java.version} + + org.springframework.boot spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + @@ -180,7 +212,7 @@ org.sonarsource.scanner.maven sonar-maven-plugin - 3.3.0.603 + 3.11.0.3922 verify @@ -191,6 +223,12 @@ + + + true + src/main/resources + + src/test/resources diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/LoggingAspect.java b/src/main/java/it/gov/pagopa/wispconverter/config/LoggingAspect.java index f7768dea..2a0e8cab 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/LoggingAspect.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/LoggingAspect.java @@ -16,9 +16,9 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.annotation.PostConstruct; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; import java.util.UUID; diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/MappingsConfiguration.java b/src/main/java/it/gov/pagopa/wispconverter/config/MappingsConfiguration.java deleted file mode 100644 index 5c94b060..00000000 --- a/src/main/java/it/gov/pagopa/wispconverter/config/MappingsConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -package it.gov.pagopa.wispconverter.config; - - -import org.modelmapper.ModelMapper; -import org.modelmapper.convention.MatchingStrategies; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class MappingsConfiguration { - - @Bean - ModelMapper modelMapper() { - ModelMapper mapper = new ModelMapper(); - mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); - return mapper; - } - -} diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/OpenApiConfig.java b/src/main/java/it/gov/pagopa/wispconverter/config/OpenApiConfig.java index b6ad0091..266fb3ba 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/OpenApiConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/OpenApiConfig.java @@ -17,7 +17,7 @@ import java.util.Objects; import java.util.Optional; -import org.springdoc.core.customizers.OpenApiCustomiser; +import org.springdoc.core.customizers.OpenApiCustomizer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -49,7 +49,7 @@ public OpenAPI customOpenAPI( } @Bean - public OpenApiCustomiser sortOperationsAlphabetically() { + public OpenApiCustomizer sortOperationsAlphabetically() { return openApi -> { Paths paths = openApi @@ -86,7 +86,7 @@ public OpenApiCustomiser sortOperationsAlphabetically() { } @Bean - public OpenApiCustomiser addCommonHeaders() { + public OpenApiCustomizer addCommonHeaders() { return openApi -> openApi .getPaths() diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/RedisConfig.java b/src/main/java/it/gov/pagopa/wispconverter/config/RedisConfig.java index 49a83ad4..eaead7e9 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/RedisConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/RedisConfig.java @@ -46,8 +46,7 @@ public LettuceConnectionFactory registerRedisConnectionFactory() { public RedisTemplate registerRedisSimpleTemplate(final LettuceConnectionFactory connectionFactory, ObjectMapper objectMapper) { RedisTemplate template = new RedisTemplate<>(); template.setKeySerializer(new StringRedisSerializer()); - Jackson2JsonRedisSerializer redisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); - redisSerializer.setObjectMapper(objectMapper); + Jackson2JsonRedisSerializer redisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class); template.setValueSerializer(redisSerializer); template.setConnectionFactory(connectionFactory); return template; diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/RequestFilter.java b/src/main/java/it/gov/pagopa/wispconverter/config/RequestFilter.java index aba441ff..f31d927e 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/RequestFilter.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/RequestFilter.java @@ -4,13 +4,9 @@ import java.io.IOException; import java.util.UUID; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/ResponseValidator.java b/src/main/java/it/gov/pagopa/wispconverter/config/ResponseValidator.java index cbc80593..c7a2dc3d 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/ResponseValidator.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/ResponseValidator.java @@ -2,9 +2,8 @@ import it.gov.pagopa.wispconverter.exception.AppException; -import java.util.Set; -import javax.validation.ConstraintViolation; -import javax.validation.Validator; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validator; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint; @@ -14,6 +13,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import java.util.Set; @Aspect @Component @@ -24,7 +24,7 @@ public class ResponseValidator { /** - * This method validates the response annotated with the {@link javax.validation.constraints} + * This method validates the response annotated with the {@link jakarta.validation.constraints} * * @param joinPoint not used * @param result the response to validate diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/ServiceController.java b/src/main/java/it/gov/pagopa/wispconverter/controller/ServiceController.java index f6d07221..1e3c26f7 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/ServiceController.java +++ b/src/main/java/it/gov/pagopa/wispconverter/controller/ServiceController.java @@ -1,5 +1,6 @@ package it.gov.pagopa.wispconverter.controller; +import jakarta.xml.bind.JAXBElement; import lombok.extern.slf4j.Slf4j; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; @@ -7,7 +8,6 @@ import org.springframework.ws.server.endpoint.annotation.ResponsePayload; import org.springframework.ws.soap.server.endpoint.annotation.SoapAction; -import javax.xml.bind.JAXBElement; @Endpoint @Slf4j diff --git a/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java b/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java index a638c217..fa143ae0 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java @@ -1,7 +1,7 @@ package it.gov.pagopa.wispconverter.exception; import java.util.Formatter; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import lombok.EqualsAndHashCode; import lombok.Value; diff --git a/src/main/java/it/gov/pagopa/wispconverter/exception/ErrorHandler.java b/src/main/java/it/gov/pagopa/wispconverter/exception/ErrorHandler.java index ce0ec7bf..4a2f2fba 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/ErrorHandler.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/ErrorHandler.java @@ -1,17 +1,16 @@ package it.gov.pagopa.wispconverter.exception; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import feign.FeignException; import it.gov.pagopa.wispconverter.model.ProblemJson; import java.util.ArrayList; import java.util.List; +import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.TypeMismatchException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.FieldError; @@ -42,8 +41,7 @@ public class ErrorHandler extends ResponseEntityExceptionHandler { * @return a {@link ProblemJson} as response with the cause and with a 400 as HTTP status */ @Override - public ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException ex, - HttpHeaders headers, HttpStatus status, WebRequest request) { + protected ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { log.warn("Input not readable: ", ex); var errorResponse = ProblemJson.builder() .status(HttpStatus.BAD_REQUEST.value()) @@ -63,9 +61,7 @@ public ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadabl * @return a {@link ProblemJson} as response with the cause and with a 400 as HTTP status */ @Override - public ResponseEntity handleMissingServletRequestParameter( - MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, - WebRequest request) { + protected ResponseEntity handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { log.warn("Missing request parameter: ", ex); var errorResponse = ProblemJson.builder() .status(HttpStatus.BAD_REQUEST.value()) @@ -86,8 +82,7 @@ public ResponseEntity handleMissingServletRequestParameter( * @return a {@code ResponseEntity} instance */ @Override - protected ResponseEntity handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers, - HttpStatus status, WebRequest request) { + protected ResponseEntity handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { log.warn("Type mismatch: ", ex); var errorResponse = ProblemJson.builder() .status(HttpStatus.BAD_REQUEST.value()) @@ -108,8 +103,7 @@ protected ResponseEntity handleTypeMismatch(TypeMismatchException ex, Ht * @return a {@link ProblemJson} as response with the cause and with a 400 as HTTP status */ @Override - protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, - HttpHeaders headers, HttpStatus status, WebRequest request) { + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { List details = new ArrayList<>(); for (FieldError error : ex.getBindingResult().getFieldErrors()) { details.add(error.getField() + ": " + error.getDefaultMessage()); @@ -124,9 +118,9 @@ protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotV return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } - @ExceptionHandler({javax.validation.ConstraintViolationException.class}) + @ExceptionHandler({ConstraintViolationException.class}) public ResponseEntity handleConstraintViolationException( - final javax.validation.ConstraintViolationException ex, final WebRequest request) { + final ConstraintViolationException ex, final WebRequest request) { log.warn("Validation Error raised:", ex); var errorResponse = ProblemJson.builder() .status(HttpStatus.BAD_REQUEST.value()) @@ -137,41 +131,6 @@ public ResponseEntity handleConstraintViolationException( } - /** - * Handle if a {@link FeignException} is raised - * - * @param ex {@link FeignException} exception raised - * @param request from frontend - * @return a {@link ProblemJson} as response with the cause and with an appropriated HTTP status - */ - @ExceptionHandler({FeignException.class}) - public ResponseEntity handleFeignException(final FeignException ex, final WebRequest request) { - log.warn("FeignException raised: ", ex); - - ProblemJson problem; - if (ex.responseBody().isPresent()) { - var body = new String(ex.responseBody().get().array(), StandardCharsets.UTF_8); - try { - problem = new ObjectMapper().readValue(body, ProblemJson.class); - } catch (JsonProcessingException e) { - problem = ProblemJson.builder() - .status(HttpStatus.BAD_GATEWAY.value()) - .title(AppError.RESPONSE_NOT_READABLE.getTitle()) - .detail(AppError.RESPONSE_NOT_READABLE.getDetails()) - .build(); - } - } else { - problem = ProblemJson.builder() - .status(HttpStatus.BAD_GATEWAY.value()) - .title("No Response Body") - .detail("Error with external dependency") - .build(); - } - - return new ResponseEntity<>(problem, HttpStatus.valueOf(problem.getStatus())); - } - - /** * Handle if a {@link AppException} is raised * diff --git a/src/main/java/it/gov/pagopa/wispconverter/model/ProblemJson.java b/src/main/java/it/gov/pagopa/wispconverter/model/ProblemJson.java index 7b28fbd8..e2ac7607 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/model/ProblemJson.java +++ b/src/main/java/it/gov/pagopa/wispconverter/model/ProblemJson.java @@ -4,8 +4,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 1e898947..5b28306e 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -1,7 +1,5 @@ # Info info.properties.environment=local + # Logging -logging.level.root=INFO logging.level.it.gov.pagopa=DEBUG -# CORS configuration -cors.configuration={"origins": ["*"], "methods": ["*"]} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index aa1fca24..cb364970 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,8 +1,10 @@ # Info +info.application.name=@project.name@ info.application.artifactId=@project.artifactId@ info.application.version=@project.version@ info.application.description=@project.description@ info.properties.environment=${ENV:azure} + # Actuator management.endpoints.web.exposure.include=health,info management.endpoints.jmx.exposure.include=health,info @@ -10,17 +12,23 @@ management.info.env.enabled=true management.endpoint.health.probes.enabled=true management.health.livenessState.enabled=true management.health.readinessState.enabled=true + # Openapi springdoc.writer-with-order-by-keys=true springdoc.writer-with-default-pretty-printer=true + # Server server.servlet.context-path=/ server.port=8080 + # Logging logging.level.root=${DEFAULT_LOGGING_LEVEL:INFO} logging.level.it.gov.pagopa=${APP_LOGGING_LEVEL:INFO} +otel.service.name=${OTEL_SERVICE_NAME:pagopa-wisp-converter} + # CORS configuration -cors.configuration=${CORS_CONFIGURATION:'{"origins": ["*"], "methods": ["*"]}'} +cors.configuration=${CORS_CONFIGURATION:{"origins": ["*"], "methods": ["*"]}} + # Application properties spring.redis.host=${REDIS_HOST} spring.redis.port=${REDIS_PORT} diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index f7beb7e2..222570ed 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -19,11 +19,13 @@ - + + + ${OTEL_SERVICE_NAME} - ${ECS_SERVICE_VERSION} + ${SERVICE_VERSION} ${ENV} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index a3810704..116bcce7 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,13 +1,39 @@ +spring.profiles.active=test + # Info +info.application.name=@project.name@ info.application.artifactId=@project.artifactId@ info.application.version=@project.version@ info.application.description=@project.description@ info.properties.environment=test + +# Actuator +management.endpoints.web.exposure.include=health,info +management.endpoints.jmx.exposure.include=health,info +management.info.env.enabled=true +management.endpoint.health.probes.enabled=true +management.health.livenessState.enabled=true +management.health.readinessState.enabled=true + # Openapi springdoc.writer-with-order-by-keys=true springdoc.writer-with-default-pretty-printer=true -# logging -logging.level.root=INFO -logging.level.it.gov.pagopa=INFO + +# Server +# TODO: set your base path +server.servlet.context-path=/ +server.port=8080 + +# Logging +logging.level.root=${DEFAULT_LOGGING_LEVEL:INFO} +logging.level.it.gov.pagopa=${APP_LOGGING_LEVEL:DEBUG} + +otel.service.name=${OTEL_SERVICE_NAME:pagopa-wisp-converter-technical-support} + # CORS configuration -cors.configuration={"origins": ["*"], "methods": ["*"]} +cors.configuration=${CORS_CONFIGURATION:{"origins": ["*"], "methods": ["*"]}} + +# Application properties +spring.redis.host=${REDIS_HOST:na} +spring.redis.port=${REDIS_PORT:6379} +spring.redis.password=${REDIS_PASSWORD:na}