From ca8291df7a42479a60068becf876cca4c4ac7d51 Mon Sep 17 00:00:00 2001 From: maxsca <130107847+maxsca@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:23:17 +0100 Subject: [PATCH 1/5] NOD-784 upgrade wsdl generation --- .DS_Store | Bin 6148 -> 10244 bytes .../wispconverter/config/WebMvcConfig.java | 90 ++++++--- .../controller/RedirectController.java | 1 + .../controller/advice/ErrorHandler.java | 139 ------------- .../advice/GlobalExceptionHandler.java | 189 ++++++++++++++++++ .../advice/model/ApiErrorResponse.java | 131 ++++++------ .../exception/AppClientException.java | 2 +- .../exception/AppErrorCodeMessageEnum.java | 37 ++-- .../wispconverter/exception/AppException.java | 54 +++-- .../wispconverter/util/AppErrorUtil.java | 79 ++++---- .../util/aspect/LoggingAspect.java | 44 ++-- src/main/resources/application.properties | 2 + .../resources/messages/messages_en.properties | 3 +- .../resources/messages/messages_it.properties | 3 +- 14 files changed, 452 insertions(+), 322 deletions(-) delete mode 100644 src/main/java/it/gov/pagopa/wispconverter/controller/advice/ErrorHandler.java create mode 100644 src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java diff --git a/.DS_Store b/.DS_Store index ee771938787a1bb39cadddab0eb4f7463f2ead2b..7d93fd66fc0f6b37a369cd4d1f7e8e3e8c49b70b 100644 GIT binary patch literal 10244 zcmeHMO=uHQ5S}$j)1pF@f2SU=^?mSOu&C z|AGSe&ZeVtqqg>H6|f3e1v~|4en{d;Hf3yGTQzmyMJ)l)M)9^f@H4IhR8G>^l(BVf zRVqGHuO1we>X;>lqtnr!q;Rw;W9!=LbZ~S!I0o4Ow0Ov0lCA9zfBVyHtwwak#@vTsIuIgevU?!Ee~wP5+2!_w60`2k;q#GfYo zE)Ty9HEIvIDtR2d9vsE_M1FX>1U!%PS~*hk`%e6*txMQz%aYa44EJ#^0QJcOFTH-E zayf$_zrfWmAJUa}x^i$uBFE+tnRz+(%%Z1*h-mhW;0S@QUxppnCtS$FC1g;Q47z%d zf$(zj{ob$&}_6ZPE9V?Kgcg}PZ4em z`(ha`KowfXMgL~$<=9V4X9w=QRc+7mIeKt}z}M}cQ1~^hJx?6e*l>|iFMi6wSj)Tx z-HXU-)f~=s`m)zfZR9oEZY_DDEvLf`_be!#XELhBJ*scH%av)huY2K^}T!V)z=m#9}R2Gm31bm&N$YX#kMG5y|u>w0*yC) z{DeP(bAK|&`jdDLXBi$P`6P%>1o>1UE0m3-9yL82fBEp&#$0LgIIiC-@Hz+%=iwUm z*(%NwIXNdpZw}sQ^>gf#eYbYpo>Oy`cm`(>7Q=Z&@78@hCNkA>(JklEVU|)9Vh^i; zRlq7>6<9|KM0Bl5+W*IWfUy7n*O4N&RI9-HQ^1L)GwDIBJM0G`?X@TIJdY3d Jr~D7=|3B~$E5!f+ delta 130 zcmZn(XfcprU|?W$DortDU=RQ@Ie-{MGqg=C6q~50D9Q+A12Ir6m7%08xF|0tKQDb^ zp*kbu<~NekY#SRA7#Fj1a0oJkGy&Cd0|{3kZrfP+oq009iY_O}gabg#FxiGjdUApa OJ1fXehRyLjGnfJTn-}^3 diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java b/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java index f875884e..c80e0138 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java @@ -1,20 +1,29 @@ package it.gov.pagopa.wispconverter.config; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import it.gov.pagopa.wispconverter.config.model.AppCors; import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.http.ProblemDetail; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.converter.json.ProblemDetailJacksonMixin; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -28,6 +37,31 @@ public class WebMvcConfig implements WebMvcConfigurer { @Value("${cors.configuration}") private String corsConfiguration; + private static final String dateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"; + +// @Bean +// public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { +// return builder -> { +// builder.mixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class); +// builder.simpleDateFormat(dateTimeFormat); +// builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat))); +// }; +// } + + +// @Autowired +// private ObjectMapper objectMapper; +// @Bean +// public ObjectMapper objectMapper(){ +// ObjectMapper objectMapper = new ObjectMapper(); +// objectMapper.addMixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class); +// return objectMapper; +// } +// @Bean +// public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){ +// MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(objectMapper); +// return mappingJackson2HttpMessageConverter; +// } @SneakyThrows @Override @@ -39,32 +73,40 @@ public void addCorsMappings(CorsRegistry registry) { .allowedMethods(appCors.getMethods()); } - @Bean - public LocaleResolver localeResolver() { - AcceptHeaderLocaleResolver acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver(); - acceptHeaderLocaleResolver.setDefaultLocale(Locale.ENGLISH); - acceptHeaderLocaleResolver.setSupportedLocales(locales); - return acceptHeaderLocaleResolver; - } +// @Bean +// public Jackson2ObjectMapperBuilder jacksonBuilder() { +// Jackson2ObjectMapperBuilder b = new Jackson2ObjectMapperBuilder(); +// b.indentOutput(true).mixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class); +// return b; +// } - @Bean - public MessageSource messageSource() { - ReloadableResourceBundleMessageSource messageSource = - new ReloadableResourceBundleMessageSource(); - messageSource.setBasename("classpath:messages"); - messageSource.setDefaultEncoding("UTF-8"); - messageSource.setUseCodeAsDefaultMessage(true); - return messageSource; - } - @Primary - @Bean - @Override - public LocalValidatorFactoryBean getValidator() { - LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean(); - bean.setValidationMessageSource(messageSource()); - return bean; - } +// @Bean +// public LocaleResolver localeResolver() { +// AcceptHeaderLocaleResolver acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver(); +// acceptHeaderLocaleResolver.setDefaultLocale(Locale.ENGLISH); +// acceptHeaderLocaleResolver.setSupportedLocales(locales); +// return acceptHeaderLocaleResolver; +// } +// +// @Bean +// public MessageSource messageSource() { +// ReloadableResourceBundleMessageSource messageSource = +// new ReloadableResourceBundleMessageSource(); +// messageSource.setBasename("classpath:messages"); +// messageSource.setDefaultEncoding("UTF-8"); +// messageSource.setUseCodeAsDefaultMessage(true); +// return messageSource; +// } + +// @Primary +// @Bean +// @Override +// public LocalValidatorFactoryBean getValidator() { +// LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean(); +// bean.setValidationMessageSource(messageSource()); +// return bean; +// } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/RedirectController.java b/src/main/java/it/gov/pagopa/wispconverter/controller/RedirectController.java index 42bf3f3f..f7c4ed25 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/RedirectController.java +++ b/src/main/java/it/gov/pagopa/wispconverter/controller/RedirectController.java @@ -13,6 +13,7 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/ErrorHandler.java b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/ErrorHandler.java deleted file mode 100644 index 1f24ad4e..00000000 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/ErrorHandler.java +++ /dev/null @@ -1,139 +0,0 @@ -package it.gov.pagopa.wispconverter.controller.advice; - -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.ExampleObject; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import it.gov.pagopa.wispconverter.controller.advice.model.ApiErrorResponse; -import it.gov.pagopa.wispconverter.exception.AppClientException; -import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; -import it.gov.pagopa.wispconverter.exception.AppException; -import it.gov.pagopa.wispconverter.util.AppErrorUtil; -import jakarta.validation.ConstraintViolationException; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.tuple.Pair; -import org.springframework.http.*; -import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; - -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * All Exceptions are handled by this class - */ -@ControllerAdvice -@Slf4j -@RequiredArgsConstructor -public class ErrorHandler extends ResponseEntityExceptionHandler { - - private final AppErrorUtil appErrorUtil; - - @ApiResponses(value = { - @ApiResponse(responseCode = "500", description = "Internal Server Error", content = { - @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiErrorResponse.class), examples = {@ExampleObject( - """ - { - "errorId": "68ce8c6a-6d53-486c-97fe-79430d24fb7d", - "timestamp": "2023-10-09T08:01:39.421224Z", - "httpStatusCode": 500, - "httpStatusDescription": "Internal Server Error", - "appErrorCode": "WIC-0500", - "message": "An unexpected error has occurred. Please contact support" - } - """ - )}) - }), - @ApiResponse(responseCode = "400", description = "Bad Request", content = { - @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiErrorResponse.class), examples = {@ExampleObject( - """ - { - "timestamp": "2023-10-09T07:53:14.077792Z", - "httpStatusCode": 400, - "httpStatusDescription": "Bad Request", - "appErrorCode": "WIC-0400", - "message": "Bad request", - "errors": [ - { - "message": "Field error in ..." - } - ] - } - """ - )}) - }), - @ApiResponse(responseCode = "404", description = "Not found", content = { - @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiErrorResponse.class), examples = {@ExampleObject( - """ - { - "timestamp": "2023-10-09T07:53:43.367312Z", - "httpStatusCode": 404, - "httpStatusDescription": "Not Found", - "appErrorCode": "WIC-0404", - "message": "Request POST /api/v1/..... not found" - } - """ - )}) - }) - }) - @ExceptionHandler({AppException.class, AppClientException.class}) - public ResponseEntity handleAppException(AppException appEx) { - Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, null, null); - return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) - .body(httpStatusApiErrorResponsePair.getRight()); - } - - @Override - protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { - List errorMessages = ex.getBindingResult().getAllErrors().stream() - .map(oe -> ApiErrorResponse.ErrorMessage.builder().message(oe.toString()).build()) - .collect(Collectors.toList()); - AppException appEx = new AppException(ex, AppErrorCodeMessageEnum.BAD_REQUEST); - Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, null, errorMessages); - return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) - .body(httpStatusApiErrorResponsePair.getRight()); - } - - @ExceptionHandler(Exception.class) - public ResponseEntity handleGenericException(Exception ex, WebRequest request) { - String errorId = UUID.randomUUID().toString(); - log.error(String.format("ExceptionHandler: ErrorId=[%s] %s", errorId, ex.getMessage()), ex); - - AppException appEx = new AppException(ex, AppErrorCodeMessageEnum.ERROR); - // errorId viene usato solo per i casi di eccezioni non gestite - Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, errorId, null); - return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) - .body(httpStatusApiErrorResponsePair.getRight()); - } - - @ExceptionHandler(ConstraintViolationException.class) - public final ResponseEntity handleConstraintViolation(ConstraintViolationException ex, WebRequest request) { - List errorMessages = ex.getConstraintViolations().stream() - .map(oe -> ApiErrorResponse.ErrorMessage.builder().message(oe.getMessage()).build()) - .collect(Collectors.toList()); - AppException appEx = new AppException(ex, AppErrorCodeMessageEnum.BAD_REQUEST); - Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, null, errorMessages); - return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) - .body(httpStatusApiErrorResponsePair.getRight()); - } - - @Override - protected ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { - List errorMessages = Stream.of(ex.getCause().getMessage()) - .map(oe -> ApiErrorResponse.ErrorMessage.builder().message(oe).build()) - .collect(Collectors.toList()); - AppException appEx = new AppException(ex, AppErrorCodeMessageEnum.BAD_REQUEST); - Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, null, errorMessages); - return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) - .body(httpStatusApiErrorResponsePair.getRight()); - } - -} diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java new file mode 100644 index 00000000..5b5b1c7d --- /dev/null +++ b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java @@ -0,0 +1,189 @@ +package it.gov.pagopa.wispconverter.controller.advice; + +import it.gov.pagopa.wispconverter.exception.AppClientException; +import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; +import it.gov.pagopa.wispconverter.exception.AppException; +import it.gov.pagopa.wispconverter.util.Constants; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.http.*; +import org.springframework.util.Assert; +import org.springframework.web.ErrorResponse; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import java.net.URI; +import java.time.Instant; +import java.util.Optional; +import java.util.UUID; + +import static it.gov.pagopa.wispconverter.util.Constants.HEADER_REQUEST_ID; +import static it.gov.pagopa.wispconverter.util.aspect.LoggingAspect.OPERATION_ID; + +/** + * All Exceptions are handled by this class + */ +//@RestControllerAdvice +@Slf4j +@RequiredArgsConstructor +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + + // private final MessageSource messageSource; + +// @ExceptionHandler(AppException.class) +// ProblemDetail handleAppException(AppException e) { +// return forAppException(e); +// } +// +// private static ProblemDetail forAppException(AppException e) { +// Assert.notNull(e, "AppException is required"); +// AppErrorCodeMessageEnum error = e.getError(); +// +// ProblemDetail problemDetail = e.getBody(); +// problemDetail.setType(URI.create("https://pagopa.it/errors/"+getAppCode(error))); +// problemDetail.setTitle("error-code."+error.name()+".title"); +// problemDetail.setDetail("error-code."+error.name()+".detail"); +// problemDetail.setProperty("timestamp", Instant.now()); +// problemDetail.setProperty("error-code", getAppCode(error)); +// String operationId = MDC.get(OPERATION_ID); +// if(operationId!=null){ +// problemDetail.setProperty("operation-id", operationId); +// } +// return problemDetail; +// } +// +// private static String getAppCode(AppErrorCodeMessageEnum error){ +// return String.format("%s-%s", Constants.SERVICE_CODE_APP, error.getCode()); +// } + +// private ErrorResponse forAppClientException(AppClientException e) { +// Assert.notNull(e, "AppClientException is required"); +// AppErrorCodeMessageEnum codeMessage = e.getError(); +// +// ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(codeMessage.getStatus(), codeMessage.getReason()); +// problemDetail.setProperty("timestamp", Instant.now()); +// problemDetail.setProperty("client-error-code", String.format("%s-%s", Constants.SERVICE_CODE_APP, codeMessage.getCode())); +// +// Optional requestIdOpt = Optional.ofNullable(MDC.get(HEADER_REQUEST_ID)); +// requestIdOpt.ifPresent(requestId -> problemDetail.setProperty(HEADER_REQUEST_ID.toLowerCase(), requestId)); +// +// String errorId = UUID.randomUUID().toString(); +// problemDetail.setProperty("error-id", errorId); +// +// return ErrorResponse.builder(e, problemDetail) +// .detailMessageCode(codeMessage.getMessageDetailCode()) +// .detailMessageArguments(e.getArgs()) +// .build(messageSource, LocaleContextHolder.getLocale()); +// } + + + // private final AppErrorUtil appErrorUtil; +// private final MessageSource messageSource; +// +// @ApiResponses(value = { +// @ApiResponse(responseCode = "500", description = "Internal Server Error", content = { +// @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiErrorResponse.class), examples = {@ExampleObject( +// """ +// { +// "errorId": "68ce8c6a-6d53-486c-97fe-79430d24fb7d", +// "timestamp": "2023-10-09T08:01:39.421224Z", +// "httpStatusCode": 500, +// "httpStatusDescription": "Internal Server Error", +// "appErrorCode": "WIC-0500", +// "message": "An unexpected error has occurred. Please contact support" +// } +// """ +// )}) +// }), +// @ApiResponse(responseCode = "400", description = "Bad Request", content = { +// @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiErrorResponse.class), examples = {@ExampleObject( +// """ +// { +// "timestamp": "2023-10-09T07:53:14.077792Z", +// "httpStatusCode": 400, +// "httpStatusDescription": "Bad Request", +// "appErrorCode": "WIC-0400", +// "message": "Bad request", +// "errors": [ +// { +// "message": "Field error in ..." +// } +// ] +// } +// """ +// )}) +// }), +// @ApiResponse(responseCode = "404", description = "Not found", content = { +// @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiErrorResponse.class), examples = {@ExampleObject( +// """ +// { +// "timestamp": "2023-10-09T07:53:43.367312Z", +// "httpStatusCode": 404, +// "httpStatusDescription": "Not Found", +// "appErrorCode": "WIC-0404", +// "message": "Request POST /api/v1/..... not found" +// } +// """ +// )}) +// }) +// }) +// @ExceptionHandler({AppException.class, AppClientException.class}) +// public ResponseEntity handleAppException(AppException appEx) { +// Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, null, null); +// return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) +// .body(httpStatusApiErrorResponsePair.getRight()); +// } +// +// @Override +// protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { +// List errorMessages = ex.getBindingResult().getAllErrors().stream() +// .map(oe -> ApiErrorResponse.ErrorMessage.builder().message(oe.toString()).build()) +// .collect(Collectors.toList()); +// AppException appEx = new AppException(ex, AppErrorCodeMessageEnum.BAD_REQUEST); +// Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, null, errorMessages); +// return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) +// .body(httpStatusApiErrorResponsePair.getRight()); +// } +// +// @ExceptionHandler(Exception.class) +// public ResponseEntity handleGenericException(Exception ex, WebRequest request) { +// String errorId = UUID.randomUUID().toString(); +// log.error(String.format("ExceptionHandler: ErrorId=[%s] %s", errorId, ex.getMessage()), ex); +// +// AppException appEx = new AppException(ex, AppErrorCodeMessageEnum.ERROR); +// // errorId viene usato solo per i casi di eccezioni non gestite +// Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, errorId, null); +// return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) +// .body(httpStatusApiErrorResponsePair.getRight()); +// } +// +// @ExceptionHandler(ConstraintViolationException.class) +// public final ResponseEntity handleConstraintViolation(ConstraintViolationException ex, WebRequest request) { +// List errorMessages = ex.getConstraintViolations().stream() +// .map(oe -> ApiErrorResponse.ErrorMessage.builder().message(oe.getMessage()).build()) +// .collect(Collectors.toList()); +// AppException appEx = new AppException(ex, AppErrorCodeMessageEnum.BAD_REQUEST); +// Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, null, errorMessages); +// return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) +// .body(httpStatusApiErrorResponsePair.getRight()); +// } +// +// @Override +// protected ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { +// List errorMessages = Stream.of(ex.getCause().getMessage()) +// .map(oe -> ApiErrorResponse.ErrorMessage.builder().message(oe).build()) +// .collect(Collectors.toList()); +// AppException appEx = new AppException(ex, AppErrorCodeMessageEnum.BAD_REQUEST); +// Pair httpStatusApiErrorResponsePair = appErrorUtil.buildApiErrorResponse(appEx, null, errorMessages); +// return ResponseEntity.status(httpStatusApiErrorResponsePair.getLeft()) +// .body(httpStatusApiErrorResponsePair.getRight()); +// } + +} diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/model/ApiErrorResponse.java b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/model/ApiErrorResponse.java index 9205a4c0..c2e600be 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/model/ApiErrorResponse.java +++ b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/model/ApiErrorResponse.java @@ -1,65 +1,66 @@ -package it.gov.pagopa.wispconverter.controller.advice.model; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; - -import java.time.Instant; -import java.util.List; - -@Getter -@Builder -@JsonPropertyOrder({ - "errorId", - "timestamp", - "httpStatusCode", - "httpStatusDescription", - "appErrorCode", - "message", - "errors" -}) -@NoArgsConstructor -@AllArgsConstructor -public class ApiErrorResponse { - - @JsonInclude(JsonInclude.Include.NON_NULL) - @Schema(example = "50905466-1881-457b-b42f-fb7b2bfb1610", description = "This field exist only if status=500") - private String errorId; - - @Schema(example = "2023-10-05T11:22:57.494928Z", requiredMode = Schema.RequiredMode.REQUIRED) - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'", timezone = "UTC") - private Instant timestamp; - - @Schema(example = "500", requiredMode = Schema.RequiredMode.REQUIRED) - private int httpStatusCode; - - @Schema(example = "Internal Server Error", requiredMode = Schema.RequiredMode.REQUIRED) - private String httpStatusDescription; - - @Schema(example = "WIC-0500", requiredMode = Schema.RequiredMode.REQUIRED) - private String appErrorCode; - - @Schema(example = "An unexpected error has occurred. Please contact support.", requiredMode = Schema.RequiredMode.REQUIRED) - private String message; - - @JsonInclude(JsonInclude.Include.NON_NULL) - private List errors; - - @Builder - @Getter - @Setter - @AllArgsConstructor - @NoArgsConstructor - @JsonPropertyOrder({"path", "message"}) - public static class ErrorMessage { - - @Schema(example = "object.field") - @JsonInclude(JsonInclude.Include.NON_NULL) - private String path; - - @Schema(example = "An unexpected error has occurred. Please contact support.", requiredMode = Schema.RequiredMode.REQUIRED) - private String message; - } -} +//package it.gov.pagopa.wispconverter.controller.advice.model; +// +//import com.fasterxml.jackson.annotation.JsonFormat; +//import com.fasterxml.jackson.annotation.JsonInclude; +//import com.fasterxml.jackson.annotation.JsonPropertyOrder; +//import io.swagger.v3.oas.annotations.media.Schema; +//import lombok.*; +//import org.springframework.http.ProblemDetail; +// +//import java.time.Instant; +//import java.util.List; +// +//@Getter +//@Builder +//@JsonPropertyOrder({ +// "errorId", +// "timestamp", +// "httpStatusCode", +// "httpStatusDescription", +// "appErrorCode", +// "message", +// "errors" +//}) +//@NoArgsConstructor +//@AllArgsConstructor +//public class ApiErrorResponse extends ProblemDetail { +// +// @JsonInclude(JsonInclude.Include.NON_NULL) +// @Schema(example = "50905466-1881-457b-b42f-fb7b2bfb1610", description = "This field exist only if status=500") +// private String errorId; +// +// @Schema(example = "2023-10-05T11:22:57.494928Z", requiredMode = Schema.RequiredMode.REQUIRED) +// @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'", timezone = "UTC") +// private Instant timestamp; +// +// @Schema(example = "500", requiredMode = Schema.RequiredMode.REQUIRED) +// private int httpStatusCode; +// +// @Schema(example = "Internal Server Error", requiredMode = Schema.RequiredMode.REQUIRED) +// private String httpStatusDescription; +// +// @Schema(example = "WIC-0500", requiredMode = Schema.RequiredMode.REQUIRED) +// private String appErrorCode; +// +// @Schema(example = "An unexpected error has occurred. Please contact support.", requiredMode = Schema.RequiredMode.REQUIRED) +// private String message; +// +// @JsonInclude(JsonInclude.Include.NON_NULL) +// private List errors; +// +// @Builder +// @Getter +// @Setter +// @AllArgsConstructor +// @NoArgsConstructor +// @JsonPropertyOrder({"path", "message"}) +// public static class ErrorMessage { +// +// @Schema(example = "object.field") +// @JsonInclude(JsonInclude.Include.NON_NULL) +// private String path; +// +// @Schema(example = "An unexpected error has occurred. Please contact support.", requiredMode = Schema.RequiredMode.REQUIRED) +// private String message; +// } +//} diff --git a/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java b/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java index 174b09a1..ca636be2 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java @@ -9,7 +9,7 @@ public class AppClientException extends AppException { private final int httpStatusCode; - public AppClientException(int httpStatusCode, AppErrorCodeMessageEnum codeMessage, Serializable... args) { + public AppClientException(int httpStatusCode, AppErrorCodeMessageEnum codeMessage, Object... args) { super(codeMessage, args); this.httpStatusCode = httpStatusCode; } diff --git a/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java b/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java index c54cc0a0..d66c5f69 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java @@ -2,30 +2,29 @@ import lombok.Getter; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; @Getter public enum AppErrorCodeMessageEnum { - UNKNOWN("0000", "UNKNOWN.error", HttpStatus.INTERNAL_SERVER_ERROR), - ERROR("0500", "system.error", HttpStatus.INTERNAL_SERVER_ERROR), - BAD_REQUEST("0400", "bad.request", HttpStatus.BAD_REQUEST), - - PARSING_("1000", "", HttpStatus.BAD_REQUEST), - PARSING_JAXB_EMPTY_NODE_ELEMENT("1001", "jaxb.node-element.empty", HttpStatus.BAD_REQUEST), - PARSING_JAXB_PARSE_ERROR("1002", "jaxb.parse", HttpStatus.BAD_REQUEST), - - PERSISTENCE_("2000", "", HttpStatus.BAD_REQUEST), - - CLIENT_("3000", "", HttpStatus.BAD_REQUEST), - + UNKNOWN("0000", "Unknown error","UNKNOWN.error", HttpStatus.INTERNAL_SERVER_ERROR), + ERROR("0500", "System error", "system.error", HttpStatus.INTERNAL_SERVER_ERROR), + BAD_REQUEST("0400", "Bad Request", "bad.request", HttpStatus.BAD_REQUEST), + PARSING_("1000", "a","a", HttpStatus.BAD_REQUEST), + PARSING_JAXB_EMPTY_NODE_ELEMENT("1001", "JAXB node element is empty","jaxb.node-element.empty", HttpStatus.BAD_REQUEST), + PARSING_JAXB_PARSE_ERROR("1002", "JAXB error during parse","jaxb.parse", HttpStatus.BAD_REQUEST), + PERSISTENCE_("2000", "b","b", HttpStatus.BAD_REQUEST), + CLIENT_("3000", "cvv","c.c", HttpStatus.BAD_REQUEST), ; - private final String errorCode; - private final String errorMessageKey; - private final HttpStatus httpStatus; + private final String code; + private final String reason; + private final String messageDetailCode; + private final HttpStatusCode status; - AppErrorCodeMessageEnum(String errorCode, String errorMessageKey, HttpStatus httpStatus) { - this.errorCode = errorCode; - this.errorMessageKey = errorMessageKey; - this.httpStatus = httpStatus; + AppErrorCodeMessageEnum(String code, String reason, String messageDetailCode, HttpStatus status) { + this.code = code; + this.reason = reason; + this.messageDetailCode = messageDetailCode; + this.status = status; } } 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 66533eea..a9ec4a53 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java @@ -1,25 +1,55 @@ package it.gov.pagopa.wispconverter.exception; +import it.gov.pagopa.wispconverter.util.Constants; +import it.gov.pagopa.wispconverter.util.aspect.LoggingAspect; import lombok.Getter; +import org.slf4j.MDC; +import org.springframework.http.ProblemDetail; +import org.springframework.util.Assert; +import org.springframework.web.ErrorResponseException; -import java.io.Serializable; +import java.net.URI; +import java.time.Instant; @Getter -public class AppException extends RuntimeException { - - private final transient AppErrorCodeMessageEnum codeMessage; +public class AppException extends ErrorResponseException { + private final AppErrorCodeMessageEnum error; private final transient Object[] args; + public AppException(AppErrorCodeMessageEnum error, Object... args) { + super(error.getStatus(), forAppErrorCodeMessageEnum(error), null, error.getMessageDetailCode(), getArgsOrNull(args)); + this.error = error; + this.args = getArgsOrNull(args); + } + public AppException(Throwable cause, AppErrorCodeMessageEnum error, Object... args) { + super(error.getStatus(), forAppErrorCodeMessageEnum(error), cause, error.getMessageDetailCode(), getArgsOrNull(args)); + this.error = error; + this.args = getArgsOrNull(args); + } + + private static Object[] getArgsOrNull(Object... args){ + return args.length > 0 ? args.clone() : null; + } + + private static ProblemDetail forAppErrorCodeMessageEnum(AppErrorCodeMessageEnum error) { + Assert.notNull(error, "AppErrorCodeMessageEnum is required"); - public AppException(Throwable cause, AppErrorCodeMessageEnum codeMessage, Serializable... args) { - super(cause); - this.codeMessage = codeMessage; - this.args = args.length > 0 ? args.clone() : null; + ProblemDetail problemDetail = ProblemDetail.forStatus(error.getStatus()); +// problemDetail.setType(URI.create("https://pagopa.it/errors/"+getAppCode(error))); +// problemDetail.setTitle("error-code."+error.name()+".title"); +// problemDetail.setDetail("error-code."+error.name()+".detail"); + problemDetail.setProperty("timestamp", Instant.now()); + problemDetail.setProperty("error-code", getAppCode(error)); + String operationId = MDC.get(LoggingAspect.OPERATION_ID); + if(operationId!=null){ + problemDetail.setProperty("operation-id", operationId); + } + return problemDetail; } - public AppException(AppErrorCodeMessageEnum codeMessage, Serializable... args) { - super(); - this.codeMessage = codeMessage; - this.args = args.length > 0 ? args.clone() : null; + private static String getAppCode(AppErrorCodeMessageEnum error){ + return String.format("%s-%s", Constants.SERVICE_CODE_APP, error.getCode()); } + + } diff --git a/src/main/java/it/gov/pagopa/wispconverter/util/AppErrorUtil.java b/src/main/java/it/gov/pagopa/wispconverter/util/AppErrorUtil.java index ef197eb6..4cd1f308 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/util/AppErrorUtil.java +++ b/src/main/java/it/gov/pagopa/wispconverter/util/AppErrorUtil.java @@ -1,38 +1,41 @@ -package it.gov.pagopa.wispconverter.util; - -import it.gov.pagopa.wispconverter.controller.advice.model.ApiErrorResponse; -import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; -import it.gov.pagopa.wispconverter.exception.AppException; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.tuple.Pair; -import org.springframework.context.MessageSource; -import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; - -import java.time.Instant; -import java.util.List; -import java.util.Locale; - -@Component -@RequiredArgsConstructor -public class AppErrorUtil { - private final MessageSource messageSource; - - public Pair buildApiErrorResponse(AppException appEx, String errorId, List errorMessageList) { - Locale locale = LocaleContextHolder.getLocale(); - AppErrorCodeMessageEnum codeMessage = appEx.getCodeMessage(); - HttpStatus status = codeMessage.getHttpStatus(); - String errorMessageKey = codeMessage.getErrorMessageKey(); - - return Pair.of(status, ApiErrorResponse.builder() - .errorId(errorId) - .timestamp(Instant.now()) - .httpStatusCode(status.value()) - .httpStatusDescription(status.getReasonPhrase()) - .appErrorCode(String.format("%s-%s", Constants.SERVICE_CODE_APP, codeMessage.getErrorCode())) - .message(messageSource.getMessage(errorMessageKey, appEx.getArgs(), locale)) - .errors(errorMessageList) - .build()); - } -} +//package it.gov.pagopa.wispconverter.util; +// +//import it.gov.pagopa.wispconverter.controller.advice.model.ApiErrorResponse; +//import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; +//import it.gov.pagopa.wispconverter.exception.AppException; +//import lombok.RequiredArgsConstructor; +//import org.apache.commons.lang3.tuple.Pair; +//import org.springframework.context.MessageSource; +//import org.springframework.context.i18n.LocaleContextHolder; +//import org.springframework.http.HttpStatus; +//import org.springframework.http.ProblemDetail; +//import org.springframework.stereotype.Component; +//import org.springframework.web.ErrorResponse; +// +//import java.time.Instant; +//import java.util.List; +//import java.util.Locale; +// +//@Component +//@RequiredArgsConstructor +//public class AppErrorUtil { +// private final MessageSource messageSource; +// +// public Pair buildApiErrorResponse(AppException appEx, String errorId, List errorMessageList) { +// Locale locale = LocaleContextHolder.getLocale(); +// AppErrorCodeMessageEnum codeMessage = appEx.getCodeMessage(); +// HttpStatus status = codeMessage.getHttpStatus(); +// String errorMessageKey = codeMessage.getErrorMessageKey(); +// +// return Pair.of(status, ApiErrorResponse.builder() +// .errorId(errorId) +// .timestamp(Instant.now()) +// .httpStatusCode(status.value()) +// .httpStatusDescription(status.getReasonPhrase()) +// .appErrorCode(String.format("%s-%s", Constants.SERVICE_CODE_APP, codeMessage.getErrorCode())) +// .message(messageSource.getMessage(errorMessageKey, appEx.getArgs(), locale)) +// .errors(errorMessageList) +// .build()); +// } +// +//} diff --git a/src/main/java/it/gov/pagopa/wispconverter/util/aspect/LoggingAspect.java b/src/main/java/it/gov/pagopa/wispconverter/util/aspect/LoggingAspect.java index c3fe6265..47f6e0ce 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/util/aspect/LoggingAspect.java +++ b/src/main/java/it/gov/pagopa/wispconverter/util/aspect/LoggingAspect.java @@ -1,6 +1,6 @@ package it.gov.pagopa.wispconverter.util.aspect; -import it.gov.pagopa.wispconverter.controller.advice.model.ApiErrorResponse; +//import it.gov.pagopa.wispconverter.controller.advice.model.ApiErrorResponse; import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; import jakarta.annotation.PostConstruct; import jakarta.servlet.http.HttpServletRequest; @@ -57,17 +57,17 @@ public class LoggingAspect { @Value("${info.properties.environment}") private String environment; - private static String getDetail(ResponseEntity result) { - if (result != null && result.getBody() != null && result.getBody().getMessage() != null) { - return result.getBody().getMessage(); - } else return AppErrorCodeMessageEnum.UNKNOWN.getErrorCode(); - } - - private static String getTitle(ResponseEntity result) { - if (result != null && result.getBody() != null && result.getBody().getAppErrorCode() != null) { - return result.getBody().getAppErrorCode(); - } else return AppErrorCodeMessageEnum.UNKNOWN.getErrorCode(); - } +// private static String getDetail(ResponseEntity result) { +// if (result != null && result.getBody() != null && result.getBody().getMessage() != null) { +// return result.getBody().getMessage(); +// } else return AppErrorCodeMessageEnum.UNKNOWN.getMessageDetail(); +// } +// +// private static String getTitle(ResponseEntity result) { +// if (result != null && result.getBody() != null && result.getBody().getAppErrorCode() != null) { +// return result.getBody().getAppErrorCode(); +// } else return AppErrorCodeMessageEnum.UNKNOWN.getMessageDetail(); +// } public static String getExecutionTime() { String startTime = MDC.get(START_TIME); @@ -139,16 +139,16 @@ public Object logApiInvocation(ProceedingJoinPoint joinPoint) throws Throwable { return result; } - @AfterReturning(value = "execution(* *..exception.ErrorHandler.*(..))", returning = "result") - public void trowingApiInvocation(JoinPoint joinPoint, ResponseEntity result) { - MDC.put(STATUS, "KO"); - MDC.put(CODE, String.valueOf(result.getStatusCode().value())); - MDC.put(RESPONSE_TIME, getExecutionTime()); - MDC.put(FAULT_CODE, getTitle(result)); - MDC.put(FAULT_DETAIL, getDetail(result)); - log.info("Failed API operation {} - error: {}", MDC.get(METHOD), result); - MDC.clear(); - } +// @AfterReturning(value = "execution(* *..exception.ErrorHandler.*(..))", returning = "result") +// public void trowingApiInvocation(JoinPoint joinPoint, ResponseEntity result) { +// MDC.put(STATUS, "KO"); +// MDC.put(CODE, String.valueOf(result.getStatusCode().value())); +// MDC.put(RESPONSE_TIME, getExecutionTime()); +// MDC.put(FAULT_CODE, getTitle(result)); +// MDC.put(FAULT_DETAIL, getDetail(result)); +// log.info("Failed API operation {} - error: {}", MDC.get(METHOD), result); +// MDC.clear(); +// } @Around(value = "repository() || service()") public Object logTrace(ProceedingJoinPoint joinPoint) throws Throwable { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 06ec121a..7a68dc2d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,6 +5,8 @@ info.application.version=@project.version@ info.application.description=@project.description@ info.properties.environment=${ENV:azure} +spring.mvc.problemdetails.enabled=true + # Actuator management.endpoints.web.exposure.include=health,info management.endpoints.jmx.exposure.include=health,info diff --git a/src/main/resources/messages/messages_en.properties b/src/main/resources/messages/messages_en.properties index 01039953..6dc6474a 100644 --- a/src/main/resources/messages/messages_en.properties +++ b/src/main/resources/messages/messages_en.properties @@ -2,4 +2,5 @@ system.error=An unexpected error has occurred. Please contact support bad.request=Bad request jaxb.node-element.empty=JAXB conversion error. Found {0} node jaxb.parse=JAXB parsing error. {0} -redirect.session-id.not-blank=SessionID passed in request must be not-blank. \ No newline at end of file +redirect.session-id.not-blank=SessionID passed in request must be not-blank. +c.c=Ciccio EN \ No newline at end of file diff --git a/src/main/resources/messages/messages_it.properties b/src/main/resources/messages/messages_it.properties index f4e4dbf2..6879d026 100644 --- a/src/main/resources/messages/messages_it.properties +++ b/src/main/resources/messages/messages_it.properties @@ -2,4 +2,5 @@ system.error=Si è verificato un errore imprevisto. Si prega di contattare l'ass bad.request=Richiesta errata jaxb.node-element.empty=Errore di conversione JAXB. Trovati {0} nodi jaxb.parse=Errore di parsing JAXB. {0} -redirect.session-id.not-blank=Il SessionID passato nella richiesta deve essere una stringa non vuota. \ No newline at end of file +redirect.session-id.not-blank=Il SessionID passato nella richiesta deve essere una stringa non vuota. +c.c=Ciccio IT \ No newline at end of file From c1b8a3d78c12f848ebbb967df2af8d59cf934c2c Mon Sep 17 00:00:00 2001 From: maxsca <130107847+maxsca@users.noreply.github.com> Date: Fri, 29 Mar 2024 18:11:17 +0100 Subject: [PATCH 2/5] NOD-784 upgrade wsdl generation --- .../wispconverter/config/RedisConfig.java | 12 ++-- .../wispconverter/config/WebMvcConfig.java | 53 +++++++++++----- .../advice/GlobalExceptionHandler.java | 32 ++++------ .../exception/AppClientException.java | 8 ++- .../exception/AppErrorCodeMessageEnum.java | 24 ++++--- .../wispconverter/exception/AppException.java | 62 ++++++++++++++++--- .../wispconverter/service/CacheService.java | 4 +- .../service/ConverterService.java | 6 +- .../service/DebtPositionService.java | 2 +- .../service/NAVGeneratorService.java | 4 +- .../wispconverter/util/JaxbElementUtil.java | 4 +- .../util/aspect/ResponseValidator.java | 2 +- src/main/resources/application.properties | 3 +- .../i18n/messages/messages.properties | 8 +++ .../messages/messages_en.properties | 4 +- .../messages/messages_it.properties | 4 +- 16 files changed, 150 insertions(+), 82 deletions(-) create mode 100644 src/main/resources/i18n/messages/messages.properties rename src/main/resources/{ => i18n}/messages/messages_en.properties (69%) rename src/main/resources/{ => i18n}/messages/messages_it.properties (73%) 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 888557d0..96ba1ec1 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/RedisConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/RedisConfig.java @@ -26,12 +26,12 @@ public class RedisConfig { @Value("${spring.redis.password}") private String password; - @Bean - public ObjectMapper registerObjectMapper() { - ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules(); - objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); - return objectMapper; - } +// @Bean +// public ObjectMapper registerObjectMapper() { +// ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules(); +// objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); +// return objectMapper; +// } @Bean public LettuceConnectionFactory registerRedisConnectionFactory() { diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java b/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java index c80e0138..2c6a0d8d 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java @@ -1,6 +1,7 @@ package it.gov.pagopa.wispconverter.config; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import it.gov.pagopa.wispconverter.config.model.AppCors; @@ -8,11 +9,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.boot.jackson.JsonMixinModule; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.http.ProblemDetail; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; @@ -23,10 +26,13 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Map; @Configuration @@ -63,6 +69,16 @@ public class WebMvcConfig implements WebMvcConfigurer { // return mappingJackson2HttpMessageConverter; // } +// @Bean +// public Jackson2ObjectMapperBuilder jacksonBuilder() { +// Jackson2ObjectMapperBuilder b = new Jackson2ObjectMapperBuilder(); +// b.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd")); +// b.mixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class); +// return b; +// } + + + @SneakyThrows @Override public void addCorsMappings(CorsRegistry registry) { @@ -81,23 +97,26 @@ public void addCorsMappings(CorsRegistry registry) { // } -// @Bean -// public LocaleResolver localeResolver() { -// AcceptHeaderLocaleResolver acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver(); -// acceptHeaderLocaleResolver.setDefaultLocale(Locale.ENGLISH); -// acceptHeaderLocaleResolver.setSupportedLocales(locales); -// return acceptHeaderLocaleResolver; -// } -// -// @Bean -// public MessageSource messageSource() { -// ReloadableResourceBundleMessageSource messageSource = -// new ReloadableResourceBundleMessageSource(); -// messageSource.setBasename("classpath:messages"); -// messageSource.setDefaultEncoding("UTF-8"); -// messageSource.setUseCodeAsDefaultMessage(true); -// return messageSource; -// } + @Bean + public LocaleResolver localeResolver() { + AcceptHeaderLocaleResolver acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver(); + acceptHeaderLocaleResolver.setDefaultLocale(Locale.ENGLISH); + acceptHeaderLocaleResolver.setSupportedLocales(locales); + return acceptHeaderLocaleResolver; + } + + + @Bean + public ResourceBundleMessageSource messageSource() { + var resourceBundleMessageSource=new ResourceBundleMessageSource(); + resourceBundleMessageSource.setBasenames("i18n/messages"); // directory with messages_XX.properties + resourceBundleMessageSource.setUseCodeAsDefaultMessage(true); +// resourceBundleMessageSource.setDefaultLocale(Locale.of("en")); + resourceBundleMessageSource.setDefaultEncoding(StandardCharsets.UTF_8.name()); + resourceBundleMessageSource.setAlwaysUseMessageFormat(true); + return resourceBundleMessageSource; + } + // @Primary // @Bean diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java index 5b5b1c7d..c7e687bd 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java +++ b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java @@ -1,46 +1,36 @@ package it.gov.pagopa.wispconverter.controller.advice; -import it.gov.pagopa.wispconverter.exception.AppClientException; -import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; import it.gov.pagopa.wispconverter.exception.AppException; -import it.gov.pagopa.wispconverter.util.Constants; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.slf4j.MDC; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.*; -import org.springframework.util.Assert; import org.springframework.web.ErrorResponse; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.ErrorResponseException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import java.net.URI; -import java.time.Instant; -import java.util.Optional; -import java.util.UUID; - -import static it.gov.pagopa.wispconverter.util.Constants.HEADER_REQUEST_ID; -import static it.gov.pagopa.wispconverter.util.aspect.LoggingAspect.OPERATION_ID; +import java.util.*; /** * All Exceptions are handled by this class */ -//@RestControllerAdvice +@RestControllerAdvice @Slf4j @RequiredArgsConstructor public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { - // private final MessageSource messageSource; + private final MessageSource messageSource; -// @ExceptionHandler(AppException.class) -// ProblemDetail handleAppException(AppException e) { -// return forAppException(e); -// } + @ExceptionHandler(ErrorResponseException.class) + ProblemDetail handleAppException(ErrorResponseException e) { + Locale locale = LocaleContextHolder.getLocale(); + String ff = messageSource.getMessage("error-code.PERSISTENCE_.title", Arrays.asList("ddd").toArray(), locale); +// return e.getBody(); + return e.getBody(); + } // // private static ProblemDetail forAppException(AppException e) { // Assert.notNull(e, "AppException is required"); diff --git a/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java b/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java index ca636be2..158c691b 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java @@ -9,8 +9,12 @@ public class AppClientException extends AppException { private final int httpStatusCode; - public AppClientException(int httpStatusCode, AppErrorCodeMessageEnum codeMessage, Object... args) { - super(codeMessage, args); + public AppClientException(int httpStatusCode, AppErrorCodeMessageEnum error, String reason, Object... args) { + super(error, reason, args); + this.httpStatusCode = httpStatusCode; + } + public AppClientException(Throwable cause, int httpStatusCode, AppErrorCodeMessageEnum error, String reason, Object... args) { + super(cause, error, reason, args); this.httpStatusCode = httpStatusCode; } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java b/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java index d66c5f69..cd3050ce 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java @@ -6,25 +6,23 @@ @Getter public enum AppErrorCodeMessageEnum { - UNKNOWN("0000", "Unknown error","UNKNOWN.error", HttpStatus.INTERNAL_SERVER_ERROR), - ERROR("0500", "System error", "system.error", HttpStatus.INTERNAL_SERVER_ERROR), - BAD_REQUEST("0400", "Bad Request", "bad.request", HttpStatus.BAD_REQUEST), - PARSING_("1000", "a","a", HttpStatus.BAD_REQUEST), - PARSING_JAXB_EMPTY_NODE_ELEMENT("1001", "JAXB node element is empty","jaxb.node-element.empty", HttpStatus.BAD_REQUEST), - PARSING_JAXB_PARSE_ERROR("1002", "JAXB error during parse","jaxb.parse", HttpStatus.BAD_REQUEST), - PERSISTENCE_("2000", "b","b", HttpStatus.BAD_REQUEST), - CLIENT_("3000", "cvv","c.c", HttpStatus.BAD_REQUEST), + UNKNOWN("0000", "Unknown error", HttpStatus.INTERNAL_SERVER_ERROR), + ERROR("0500", "System error", HttpStatus.INTERNAL_SERVER_ERROR), + BAD_REQUEST("0400", "Bad Request", HttpStatus.BAD_REQUEST), + PARSING_("1000", "a", HttpStatus.BAD_REQUEST), + PARSING_JAXB_EMPTY_NODE_ELEMENT("1001", "JAXB node element is empty", HttpStatus.BAD_REQUEST), + PARSING_JAXB_PARSE_ERROR("1002", "JAXB error during parse", HttpStatus.BAD_REQUEST), + PERSISTENCE_("2000", "Persistence error", HttpStatus.BAD_REQUEST), + CLIENT_("3000", "cvv", HttpStatus.BAD_REQUEST), ; private final String code; - private final String reason; - private final String messageDetailCode; + private final String title; private final HttpStatusCode status; - AppErrorCodeMessageEnum(String code, String reason, String messageDetailCode, HttpStatus status) { + AppErrorCodeMessageEnum(String code, String title, HttpStatus status) { this.code = code; - this.reason = reason; - this.messageDetailCode = messageDetailCode; + this.title = title; this.status = status; } } 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 a9ec4a53..759ca7e6 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java @@ -4,26 +4,32 @@ import it.gov.pagopa.wispconverter.util.aspect.LoggingAspect; import lombok.Getter; import org.slf4j.MDC; +import org.springframework.context.MessageSource; import org.springframework.http.ProblemDetail; import org.springframework.util.Assert; import org.springframework.web.ErrorResponseException; import java.net.URI; import java.time.Instant; +import java.util.Locale; @Getter public class AppException extends ErrorResponseException { private final AppErrorCodeMessageEnum error; private final transient Object[] args; - public AppException(AppErrorCodeMessageEnum error, Object... args) { - super(error.getStatus(), forAppErrorCodeMessageEnum(error), null, error.getMessageDetailCode(), getArgsOrNull(args)); + private String reason; + + public AppException(AppErrorCodeMessageEnum error, String reason, Object... args) { + super(error.getStatus(), forAppErrorCodeMessageEnum(error, reason), null, null, getArgsOrNull(args)); this.error = error; + this.reason = reason; this.args = getArgsOrNull(args); } - public AppException(Throwable cause, AppErrorCodeMessageEnum error, Object... args) { - super(error.getStatus(), forAppErrorCodeMessageEnum(error), cause, error.getMessageDetailCode(), getArgsOrNull(args)); + public AppException(Throwable cause, AppErrorCodeMessageEnum error, String reason, Object... args) { + super(error.getStatus(), forAppErrorCodeMessageEnum(error, reason), cause, null, getArgsOrNull(args)); this.error = error; + this.reason = reason; this.args = getArgsOrNull(args); } @@ -31,13 +37,14 @@ private static Object[] getArgsOrNull(Object... args){ return args.length > 0 ? args.clone() : null; } - private static ProblemDetail forAppErrorCodeMessageEnum(AppErrorCodeMessageEnum error) { + private static ProblemDetail forAppErrorCodeMessageEnum(AppErrorCodeMessageEnum error, String reason) { Assert.notNull(error, "AppErrorCodeMessageEnum is required"); ProblemDetail problemDetail = ProblemDetail.forStatus(error.getStatus()); -// problemDetail.setType(URI.create("https://pagopa.it/errors/"+getAppCode(error))); -// problemDetail.setTitle("error-code."+error.name()+".title"); -// problemDetail.setDetail("error-code."+error.name()+".detail"); + problemDetail.setType(URI.create("https://pagopa.it/errors/"+getAppCode(error))); + problemDetail.setTitle(error.getTitle()); + problemDetail.setDetail(reason); + problemDetail.setProperty("timestamp", Instant.now()); problemDetail.setProperty("error-code", getAppCode(error)); String operationId = MDC.get(LoggingAspect.OPERATION_ID); @@ -47,9 +54,46 @@ private static ProblemDetail forAppErrorCodeMessageEnum(AppErrorCodeMessageEnum return problemDetail; } + @Override + public String getTitleMessageCode() { + return "error-code."+error.name()+".title"; + } + + @Override + public String getDetailMessageCode() { + return "error-code."+error.name()+".detail"; + } + + @Override + public String getTypeMessageCode() { + return URI.create("https://pagopa.it/errors/"+getAppCode(error)).toString(); + } + + private static String getAppCode(AppErrorCodeMessageEnum error){ return String.format("%s-%s", Constants.SERVICE_CODE_APP, error.getCode()); } - +// @Override +// public ProblemDetail updateAndGetBody(MessageSource messageSource, Locale locale) { +// if (messageSource != null) { +// String type = messageSource.getMessage(getBody().getType().toString(), null, null, locale); +// if (type != null) { +// getBody().setType(URI.create(type)); +// } +// Object[] arguments = getDetailMessageArguments(messageSource, locale); +// if(getBody().getDetail() != null){ +// String detail = messageSource.getMessage(getBody().getDetail(), arguments, null, locale); +// if (detail != null) { +// getBody().setDetail(detail); +// } +// } +// +// String title = messageSource.getMessage(getTitleMessageCode(), null, null, locale); +// if (title != null) { +// getBody().setTitle(title); +// } +// } +// return getBody(); +// } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/service/CacheService.java b/src/main/java/it/gov/pagopa/wispconverter/service/CacheService.java index c86b31b4..84676b8c 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/service/CacheService.java +++ b/src/main/java/it/gov/pagopa/wispconverter/service/CacheService.java @@ -49,9 +49,9 @@ public void storeRequestMappingInCache(List rptContentDTOs, Strin } catch (FeignException e) { - throw new AppClientException(e.status(), AppErrorCodeMessageEnum.CLIENT_); + throw new AppClientException(e, e.status(), AppErrorCodeMessageEnum.CLIENT_, e.getMessage()); } catch (RedisException e) { - throw new AppException(AppErrorCodeMessageEnum.PERSISTENCE_); + throw new AppException(e, AppErrorCodeMessageEnum.PERSISTENCE_, e.getMessage()); } } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/service/ConverterService.java b/src/main/java/it/gov/pagopa/wispconverter/service/ConverterService.java index b3206759..3e0d85a6 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/service/ConverterService.java +++ b/src/main/java/it/gov/pagopa/wispconverter/service/ConverterService.java @@ -92,9 +92,9 @@ private PaymentPosition mapRPTToDebtPosition(RPTRequestDTO rptRequestDTO, RPTCon private RPTRequestEntity getRPTRequestEntity(String sessionId) { try { Optional optRPTReqEntity = this.rptRequestRepository.findById(sessionId); - return optRPTReqEntity.orElseThrow(() -> new AppException(AppErrorCodeMessageEnum.PERSISTENCE_)); + return optRPTReqEntity.orElseThrow(() -> new AppException(AppErrorCodeMessageEnum.PERSISTENCE_, String.format("User with sessionId=[%s] not found", sessionId), sessionId)); } catch (CosmosException | CosmosAccessException e) { - throw new AppException(AppErrorCodeMessageEnum.PERSISTENCE_); + throw new AppException(e, AppErrorCodeMessageEnum.PERSISTENCE_, e.getMessage()); } // TODO RE } @@ -135,7 +135,7 @@ private List getRPTContentDTO(String primitive, String payload) t .build(); }).toList(); } - default -> throw new AppException(AppErrorCodeMessageEnum.PARSING_); + default -> throw new AppException(AppErrorCodeMessageEnum.PARSING_, String.format("Primitive [%S] not valid", primitive)); } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/service/DebtPositionService.java b/src/main/java/it/gov/pagopa/wispconverter/service/DebtPositionService.java index d5e6d17c..e86c8e38 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/service/DebtPositionService.java +++ b/src/main/java/it/gov/pagopa/wispconverter/service/DebtPositionService.java @@ -43,7 +43,7 @@ public void executeBulkCreation(List rptContentDTOs) { }); } catch (FeignException e) { - throw new AppClientException(e.status(), AppErrorCodeMessageEnum.CLIENT_); + throw new AppClientException(e, e.status(), AppErrorCodeMessageEnum.CLIENT_, e.getMessage()); } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/service/NAVGeneratorService.java b/src/main/java/it/gov/pagopa/wispconverter/service/NAVGeneratorService.java index 9e04c80e..5a21acfb 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/service/NAVGeneratorService.java +++ b/src/main/java/it/gov/pagopa/wispconverter/service/NAVGeneratorService.java @@ -36,11 +36,11 @@ public String getNAVCodeFromIUVGenerator(String creditorInstitutionCode) { try { IUVGeneratorResponse response = this.iuvGeneratorClient.generate(creditorInstitutionCode, request); if (response == null) { - throw new AppException(AppErrorCodeMessageEnum.CLIENT_); + throw new AppException(AppErrorCodeMessageEnum.CLIENT_, "IUVGeneratorResponse is null"); } navCode = response.getIuv(); } catch (FeignException e) { - throw new AppClientException(e.status(), AppErrorCodeMessageEnum.CLIENT_); + throw new AppClientException(e, e.status(), AppErrorCodeMessageEnum.CLIENT_, e.getMessage()); } return navCode; } diff --git a/src/main/java/it/gov/pagopa/wispconverter/util/JaxbElementUtil.java b/src/main/java/it/gov/pagopa/wispconverter/util/JaxbElementUtil.java index b078e6f8..2c2edb55 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/util/JaxbElementUtil.java +++ b/src/main/java/it/gov/pagopa/wispconverter/util/JaxbElementUtil.java @@ -45,7 +45,7 @@ private Element convertToElement(InputSource is, String nameSpaceUri, String loc Document doc = db.parse(is); NodeList nodeList = doc.getElementsByTagNameNS(nameSpaceUri, localName); if (nodeList.getLength() == 0) { - throw new AppException(AppErrorCodeMessageEnum.PARSING_JAXB_EMPTY_NODE_ELEMENT, 0); + throw new AppException(AppErrorCodeMessageEnum.PARSING_JAXB_EMPTY_NODE_ELEMENT, "NodeList must be > 0"); } return (Element) nodeList.item(0); } catch (ParserConfigurationException | IOException | SAXException e) { @@ -62,7 +62,7 @@ public T convertToBean(Element element, Class targetType) { return jaxbElement.getValue(); } catch (JAXBException e) { log.error("Errore durante unmarshal", e); - throw new AppException(AppErrorCodeMessageEnum.PARSING_, e, e.getMessage()); + throw new AppException(e, AppErrorCodeMessageEnum.PARSING_, e.getMessage()); } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/util/aspect/ResponseValidator.java b/src/main/java/it/gov/pagopa/wispconverter/util/aspect/ResponseValidator.java index 3373102d..b4716ad4 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/util/aspect/ResponseValidator.java +++ b/src/main/java/it/gov/pagopa/wispconverter/util/aspect/ResponseValidator.java @@ -45,7 +45,7 @@ private void validateResponse(ResponseEntity response) { sb.append(error.getPropertyPath()).append(" ").append(error.getMessage()).append(". "); } var msg = StringUtils.chop(sb.toString()); - throw new AppException(AppErrorCodeMessageEnum.ERROR, "Invalid response", msg); + throw new AppException(AppErrorCodeMessageEnum.ERROR, "Invalid response"); } } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7a68dc2d..634a6525 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,7 +5,8 @@ info.application.version=@project.version@ info.application.description=@project.description@ info.properties.environment=${ENV:azure} -spring.mvc.problemdetails.enabled=true +## mange all error +#spring.mvc.throw-exception-if-no-handler-found=true # Actuator management.endpoints.web.exposure.include=health,info diff --git a/src/main/resources/i18n/messages/messages.properties b/src/main/resources/i18n/messages/messages.properties new file mode 100644 index 00000000..8cc6a276 --- /dev/null +++ b/src/main/resources/i18n/messages/messages.properties @@ -0,0 +1,8 @@ +system.error=An unexpected error has occurred. Please contact support +bad.request=Bad request +jaxb.node-element.empty=JAXB conversion error. Found {0} node +jaxb.parse=JAXB parsing error. {0} +redirect.session-id.not-blank=SessionID passed in request must be not-blank. + +error-code.PERSISTENCE_.title=Persistence error +error-code.PERSISTENCE_.detail=User with sessionId=[{0}] not found \ No newline at end of file diff --git a/src/main/resources/messages/messages_en.properties b/src/main/resources/i18n/messages/messages_en.properties similarity index 69% rename from src/main/resources/messages/messages_en.properties rename to src/main/resources/i18n/messages/messages_en.properties index 6dc6474a..8cc6a276 100644 --- a/src/main/resources/messages/messages_en.properties +++ b/src/main/resources/i18n/messages/messages_en.properties @@ -3,4 +3,6 @@ bad.request=Bad request jaxb.node-element.empty=JAXB conversion error. Found {0} node jaxb.parse=JAXB parsing error. {0} redirect.session-id.not-blank=SessionID passed in request must be not-blank. -c.c=Ciccio EN \ No newline at end of file + +error-code.PERSISTENCE_.title=Persistence error +error-code.PERSISTENCE_.detail=User with sessionId=[{0}] not found \ No newline at end of file diff --git a/src/main/resources/messages/messages_it.properties b/src/main/resources/i18n/messages/messages_it.properties similarity index 73% rename from src/main/resources/messages/messages_it.properties rename to src/main/resources/i18n/messages/messages_it.properties index 6879d026..88e9f7b0 100644 --- a/src/main/resources/messages/messages_it.properties +++ b/src/main/resources/i18n/messages/messages_it.properties @@ -3,4 +3,6 @@ bad.request=Richiesta errata jaxb.node-element.empty=Errore di conversione JAXB. Trovati {0} nodi jaxb.parse=Errore di parsing JAXB. {0} redirect.session-id.not-blank=Il SessionID passato nella richiesta deve essere una stringa non vuota. -c.c=Ciccio IT \ No newline at end of file + +error-code.PERSISTENCE_.title=Persistence error +error-code.PERSISTENCE_.detail=User with sessionId=[{0}] not found \ No newline at end of file From 858f0a9da1fdeb16c9fa6afdedf72bcdf1a91907 Mon Sep 17 00:00:00 2001 From: maxsca <130107847+maxsca@users.noreply.github.com> Date: Fri, 29 Mar 2024 18:57:46 +0100 Subject: [PATCH 3/5] NOD-784 upgrade wsdl generation --- src/main/.DS_Store | Bin 0 -> 6148 bytes .../wispconverter/config/RedisConfig.java | 9 -- .../config/UnmarshallerConfig.java | 1 - .../wispconverter/config/WebMvcConfig.java | 83 +++--------------- .../advice/GlobalExceptionHandler.java | 55 ++++++++++-- .../advice/model/ApiErrorResponse.java | 66 -------------- .../wispconverter/exception/AppException.java | 83 ++---------------- src/main/resources/.DS_Store | Bin 0 -> 8196 bytes src/main/resources/i18n/.DS_Store | Bin 0 -> 6148 bytes .../i18n/messages/messages.properties | 8 -- .../{messages => }/messages_en.properties | 0 .../{messages => }/messages_it.properties | 0 12 files changed, 66 insertions(+), 239 deletions(-) create mode 100644 src/main/.DS_Store delete mode 100644 src/main/java/it/gov/pagopa/wispconverter/controller/advice/model/ApiErrorResponse.java create mode 100644 src/main/resources/.DS_Store create mode 100644 src/main/resources/i18n/.DS_Store delete mode 100644 src/main/resources/i18n/messages/messages.properties rename src/main/resources/i18n/{messages => }/messages_en.properties (100%) rename src/main/resources/i18n/{messages => }/messages_it.properties (100%) diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ff84b25e97710375f587e147daf0458a422eb561 GIT binary patch literal 6148 zcmeHK%}T>S5Z-O8Z74zx3gRi?wPLLv8oY#BU%-eSRBB>_24lA5#~ex_51=pPgZMno z>~6%;dhjA*XJGc5ou4fGZP*{i7$4;01IA3oSPK-fWK6;yA*{_uy-y*7+jTu-_m)G#!{gwXIzd9-_av;{X*e#bnsg;opDDYwZs51 zFwa0;bxl0~PrrZv&lgdT7$64z6$896bcX|&l0I7(CWmLO1$qmLf_bIF&k``?Q4G0w d6mNq{0l$R?prf%=2p$l+2uK>JAqIYxfe(8;P9FdO literal 0 HcmV?d00001 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 96ba1ec1..f82cb60c 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/RedisConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/RedisConfig.java @@ -1,7 +1,5 @@ package it.gov.pagopa.wispconverter.config; -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -26,13 +24,6 @@ public class RedisConfig { @Value("${spring.redis.password}") private String password; -// @Bean -// public ObjectMapper registerObjectMapper() { -// ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules(); -// objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); -// return objectMapper; -// } - @Bean public LettuceConnectionFactory registerRedisConnectionFactory() { RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration(host, port); diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/UnmarshallerConfig.java b/src/main/java/it/gov/pagopa/wispconverter/config/UnmarshallerConfig.java index 9e073a71..3dfdba86 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/UnmarshallerConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/UnmarshallerConfig.java @@ -10,7 +10,6 @@ @Configuration public class UnmarshallerConfig { - @Bean @Scope("prototype") public DocumentBuilderFactory documentBuilderFactory() throws ParserConfigurationException { diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java b/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java index 2c6a0d8d..45dec7ee 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java @@ -1,25 +1,14 @@ package it.gov.pagopa.wispconverter.config; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer; -import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import it.gov.pagopa.wispconverter.config.model.AppCors; +import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; -import org.springframework.boot.jackson.JsonMixinModule; -import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; -import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.context.support.ResourceBundleMessageSource; -import org.springframework.http.ProblemDetail; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.http.converter.json.ProblemDetailJacksonMixin; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.CorsRegistry; @@ -27,15 +16,13 @@ import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.Locale; -import java.util.Map; @Configuration +@RequiredArgsConstructor public class WebMvcConfig implements WebMvcConfigurer { List locales = Arrays.asList(Locale.ENGLISH, Locale.ITALIAN); @@ -43,59 +30,16 @@ public class WebMvcConfig implements WebMvcConfigurer { @Value("${cors.configuration}") private String corsConfiguration; - private static final String dateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"; - -// @Bean -// public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { -// return builder -> { -// builder.mixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class); -// builder.simpleDateFormat(dateTimeFormat); -// builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat))); -// }; -// } - - -// @Autowired -// private ObjectMapper objectMapper; -// @Bean -// public ObjectMapper objectMapper(){ -// ObjectMapper objectMapper = new ObjectMapper(); -// objectMapper.addMixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class); -// return objectMapper; -// } -// @Bean -// public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){ -// MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(objectMapper); -// return mappingJackson2HttpMessageConverter; -// } - -// @Bean -// public Jackson2ObjectMapperBuilder jacksonBuilder() { -// Jackson2ObjectMapperBuilder b = new Jackson2ObjectMapperBuilder(); -// b.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd")); -// b.mixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class); -// return b; -// } - - @SneakyThrows @Override public void addCorsMappings(CorsRegistry registry) { - AppCors appCors = new ObjectMapper().readValue(corsConfiguration, - AppCors.class); + AppCors appCors = new ObjectMapper().readValue(corsConfiguration, AppCors.class); registry.addMapping("/**") .allowedOrigins(appCors.getOrigins()) .allowedMethods(appCors.getMethods()); } -// @Bean -// public Jackson2ObjectMapperBuilder jacksonBuilder() { -// Jackson2ObjectMapperBuilder b = new Jackson2ObjectMapperBuilder(); -// b.indentOutput(true).mixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class); -// return b; -// } - @Bean public LocaleResolver localeResolver() { @@ -109,23 +53,22 @@ public LocaleResolver localeResolver() { @Bean public ResourceBundleMessageSource messageSource() { var resourceBundleMessageSource=new ResourceBundleMessageSource(); - resourceBundleMessageSource.setBasenames("i18n/messages"); // directory with messages_XX.properties + resourceBundleMessageSource.setBasename("i18n/messages"); // directory with messages_XX.properties + resourceBundleMessageSource.setDefaultLocale(Locale.ENGLISH); resourceBundleMessageSource.setUseCodeAsDefaultMessage(true); -// resourceBundleMessageSource.setDefaultLocale(Locale.of("en")); resourceBundleMessageSource.setDefaultEncoding(StandardCharsets.UTF_8.name()); resourceBundleMessageSource.setAlwaysUseMessageFormat(true); return resourceBundleMessageSource; } - -// @Primary -// @Bean -// @Override -// public LocalValidatorFactoryBean getValidator() { -// LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean(); -// bean.setValidationMessageSource(messageSource()); -// return bean; -// } + @Primary + @Bean + @Override + public LocalValidatorFactoryBean getValidator() { + LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean(); + bean.setValidationMessageSource(messageSource()); + return bean; + } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java index c7e687bd..9076e96d 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java +++ b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java @@ -1,18 +1,23 @@ package it.gov.pagopa.wispconverter.controller.advice; +import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; import it.gov.pagopa.wispconverter.exception.AppException; +import it.gov.pagopa.wispconverter.util.Constants; +import it.gov.pagopa.wispconverter.util.aspect.LoggingAspect; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.http.*; +import org.springframework.http.ProblemDetail; +import org.springframework.util.Assert; import org.springframework.web.ErrorResponse; -import org.springframework.web.ErrorResponseException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import java.util.*; +import java.net.URI; +import java.time.Instant; /** * All Exceptions are handled by this class @@ -24,13 +29,45 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { private final MessageSource messageSource; - @ExceptionHandler(ErrorResponseException.class) - ProblemDetail handleAppException(ErrorResponseException e) { - Locale locale = LocaleContextHolder.getLocale(); - String ff = messageSource.getMessage("error-code.PERSISTENCE_.title", Arrays.asList("ddd").toArray(), locale); -// return e.getBody(); - return e.getBody(); + @ExceptionHandler(AppException.class) + public ErrorResponse handleAppException(AppException appEx) { + return ErrorResponse.builder(appEx, forAppErrorCodeMessageEnum(appEx.getError(), appEx.getReason())) + .typeMessageCode("https://pagopa.it/errors/"+getAppCode(appEx.getError())) + .titleMessageCode("error-code."+appEx.getError().name()+".title") + .detailMessageCode("error-code."+appEx.getError().name()+".detail") + .detailMessageArguments(appEx.getArgs()) + .build(messageSource, LocaleContextHolder.getLocale()); + } + + private static ProblemDetail forAppErrorCodeMessageEnum(AppErrorCodeMessageEnum error, String reason) { + Assert.notNull(error, "AppErrorCodeMessageEnum is required"); + + ProblemDetail problemDetail = ProblemDetail.forStatus(error.getStatus()); + problemDetail.setType(URI.create("https://pagopa.it/errors/"+getAppCode(error))); + problemDetail.setTitle(error.getTitle()); + problemDetail.setDetail(reason); + + problemDetail.setProperty("timestamp", Instant.now()); + problemDetail.setProperty("error-code", getAppCode(error)); + String operationId = MDC.get(LoggingAspect.OPERATION_ID); + if(operationId!=null){ + problemDetail.setProperty("operation-id", operationId); + } + return problemDetail; } + + private static String getAppCode(AppErrorCodeMessageEnum error){ + return String.format("%s-%s", Constants.SERVICE_CODE_APP, error.getCode()); + } + + +// @ExceptionHandler(AppException.class) +// ProblemDetail handleAppException(AppException e) { +// Locale locale = LocaleContextHolder.getLocale(); +// String ff = messageSource.getMessage("error-code.PERSISTENCE_.title", Arrays.asList("ddd").toArray(), locale); +//// return e.getBody(); +// return e.getBody(); +// } // // private static ProblemDetail forAppException(AppException e) { // Assert.notNull(e, "AppException is required"); diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/model/ApiErrorResponse.java b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/model/ApiErrorResponse.java deleted file mode 100644 index c2e600be..00000000 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/model/ApiErrorResponse.java +++ /dev/null @@ -1,66 +0,0 @@ -//package it.gov.pagopa.wispconverter.controller.advice.model; -// -//import com.fasterxml.jackson.annotation.JsonFormat; -//import com.fasterxml.jackson.annotation.JsonInclude; -//import com.fasterxml.jackson.annotation.JsonPropertyOrder; -//import io.swagger.v3.oas.annotations.media.Schema; -//import lombok.*; -//import org.springframework.http.ProblemDetail; -// -//import java.time.Instant; -//import java.util.List; -// -//@Getter -//@Builder -//@JsonPropertyOrder({ -// "errorId", -// "timestamp", -// "httpStatusCode", -// "httpStatusDescription", -// "appErrorCode", -// "message", -// "errors" -//}) -//@NoArgsConstructor -//@AllArgsConstructor -//public class ApiErrorResponse extends ProblemDetail { -// -// @JsonInclude(JsonInclude.Include.NON_NULL) -// @Schema(example = "50905466-1881-457b-b42f-fb7b2bfb1610", description = "This field exist only if status=500") -// private String errorId; -// -// @Schema(example = "2023-10-05T11:22:57.494928Z", requiredMode = Schema.RequiredMode.REQUIRED) -// @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'", timezone = "UTC") -// private Instant timestamp; -// -// @Schema(example = "500", requiredMode = Schema.RequiredMode.REQUIRED) -// private int httpStatusCode; -// -// @Schema(example = "Internal Server Error", requiredMode = Schema.RequiredMode.REQUIRED) -// private String httpStatusDescription; -// -// @Schema(example = "WIC-0500", requiredMode = Schema.RequiredMode.REQUIRED) -// private String appErrorCode; -// -// @Schema(example = "An unexpected error has occurred. Please contact support.", requiredMode = Schema.RequiredMode.REQUIRED) -// private String message; -// -// @JsonInclude(JsonInclude.Include.NON_NULL) -// private List errors; -// -// @Builder -// @Getter -// @Setter -// @AllArgsConstructor -// @NoArgsConstructor -// @JsonPropertyOrder({"path", "message"}) -// public static class ErrorMessage { -// -// @Schema(example = "object.field") -// @JsonInclude(JsonInclude.Include.NON_NULL) -// private String path; -// -// @Schema(example = "An unexpected error has occurred. Please contact support.", requiredMode = Schema.RequiredMode.REQUIRED) -// private String message; -// } -//} 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 759ca7e6..d0a3ac57 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java @@ -1,99 +1,30 @@ package it.gov.pagopa.wispconverter.exception; -import it.gov.pagopa.wispconverter.util.Constants; -import it.gov.pagopa.wispconverter.util.aspect.LoggingAspect; import lombok.Getter; -import org.slf4j.MDC; -import org.springframework.context.MessageSource; -import org.springframework.http.ProblemDetail; -import org.springframework.util.Assert; -import org.springframework.web.ErrorResponseException; - -import java.net.URI; -import java.time.Instant; -import java.util.Locale; @Getter -public class AppException extends ErrorResponseException { +public class AppException extends RuntimeException { private final AppErrorCodeMessageEnum error; private final transient Object[] args; - private String reason; + private final String reason; public AppException(AppErrorCodeMessageEnum error, String reason, Object... args) { - super(error.getStatus(), forAppErrorCodeMessageEnum(error, reason), null, null, getArgsOrNull(args)); + super(reason); this.error = error; this.reason = reason; this.args = getArgsOrNull(args); } + public AppException(Throwable cause, AppErrorCodeMessageEnum error, String reason, Object... args) { - super(error.getStatus(), forAppErrorCodeMessageEnum(error, reason), cause, null, getArgsOrNull(args)); + super(reason, cause); this.error = error; this.reason = reason; this.args = getArgsOrNull(args); } - private static Object[] getArgsOrNull(Object... args){ + private static Object[] getArgsOrNull(Object... args) { return args.length > 0 ? args.clone() : null; } - private static ProblemDetail forAppErrorCodeMessageEnum(AppErrorCodeMessageEnum error, String reason) { - Assert.notNull(error, "AppErrorCodeMessageEnum is required"); - - ProblemDetail problemDetail = ProblemDetail.forStatus(error.getStatus()); - problemDetail.setType(URI.create("https://pagopa.it/errors/"+getAppCode(error))); - problemDetail.setTitle(error.getTitle()); - problemDetail.setDetail(reason); - - problemDetail.setProperty("timestamp", Instant.now()); - problemDetail.setProperty("error-code", getAppCode(error)); - String operationId = MDC.get(LoggingAspect.OPERATION_ID); - if(operationId!=null){ - problemDetail.setProperty("operation-id", operationId); - } - return problemDetail; - } - - @Override - public String getTitleMessageCode() { - return "error-code."+error.name()+".title"; - } - - @Override - public String getDetailMessageCode() { - return "error-code."+error.name()+".detail"; - } - - @Override - public String getTypeMessageCode() { - return URI.create("https://pagopa.it/errors/"+getAppCode(error)).toString(); - } - - - private static String getAppCode(AppErrorCodeMessageEnum error){ - return String.format("%s-%s", Constants.SERVICE_CODE_APP, error.getCode()); - } - -// @Override -// public ProblemDetail updateAndGetBody(MessageSource messageSource, Locale locale) { -// if (messageSource != null) { -// String type = messageSource.getMessage(getBody().getType().toString(), null, null, locale); -// if (type != null) { -// getBody().setType(URI.create(type)); -// } -// Object[] arguments = getDetailMessageArguments(messageSource, locale); -// if(getBody().getDetail() != null){ -// String detail = messageSource.getMessage(getBody().getDetail(), arguments, null, locale); -// if (detail != null) { -// getBody().setDetail(detail); -// } -// } -// -// String title = messageSource.getMessage(getTitleMessageCode(), null, null, locale); -// if (title != null) { -// getBody().setTitle(title); -// } -// } -// return getBody(); -// } -} +} \ No newline at end of file diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0021aff2d41be8700b671eca8c53c71ef41bf080 GIT binary patch literal 8196 zcmeHMU2GLa6rOKe=&l=JTNWs#$kmHl3YAhYw19AXOT$mW*4~!>@Kg8RU0`LqTkr0@ z1#4sVkslxZi7{%TMiZ?siUy;;Xo3&=fDQh=@L+uMMNnUi#xpy6n-=J!hNL^m%$YOi zoSA#herF~#mobKP!Q8}HHDgSs%BiMObDP5DyxvlzXr!Dd$ev|K{gJHWWr@FZi*`H^ zM<9+s9Dz6jaRlNB+zAn&Gn*HAj&ol~<2H^!9D#Wm0lq&ZsB)T$=!Br*) z8B&7AZ5)9(0=Gthr%ySv*(TP^+?n_H?1*FgL1W`pNM+><7FJX!6>7!N%t>!F6Bt3k zPaFBeoa^yCCtK(MA^2IM?Xd$$;w@-x=8Om)Ym^SIHYL>-|Ds;Be09sZX>Y#A#I6I4(`i&Zdcwa zl4E^2&nXPMB&p09POd=8R;%M=>?ehGF7G)`m*?Ao?YRT}fpt3IGCt8PQU9Rt<%70x zvVNQ97g|+(jm{Bn>>sl7K2b%PT)d+8p8M)IZfV(>-qX=JwM46|QuSra`---2XB}(6 z@N<@H+U|+oQQHho4pL0rz&>tUc}1?o<2|l1Y)w^Zl}oDi8oj@ewVx>1!5LXg%Him0 zeT{m=Bu5T>+il-dBvg(mKT8Hg$*IpYw)?=_mV2B{qoRU9|EszVZRX4?0II zcY5(QyH}CR2@q(@TmG<)_$c*2vOqKRd=o*cobEi?cX~3wRDM;5EFCH}EDV@hLvT=eUe-F@>x64%cuUH}E_D zmMSD!Qlu(rsiaHGrFBxhv{~9AwM+Y@jQI6ZDWeY0_DV8|pWY)VqoOxH>HXVhRPCO< z`}TJnxMMTwhs8XHmQoI_NbtmJemFgiK>^wlPG_P&g#4^T2_YZi;U=t3Rj;gBRjb~; zX09CVrChO2%N+1pMWmfvD^sp$3nI2|9kCtSLc!KHJV;ob)TEGAYnwJJlzm!R#5Qat z7J^Z??@%ZYweqP|D{HEE)}~aA@qIuk&D2ga$^R9^zhYO|_XP1@3F7~t3^GA`!b7M_~R&0Oh+gyVKiO=l%KrFBGRtoB#j- literal 0 HcmV?d00001 diff --git a/src/main/resources/i18n/.DS_Store b/src/main/resources/i18n/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..bde2e3734dee541cceb148b2949e341d5a8855ad GIT binary patch literal 6148 zcmeHK%}T>S5Z-O8O(;SR3gT(OYsFeUw0H@zzJL)usMN%S8ceg&wDwR6c>sMOAH?Tz zW_Ke>^d=%@rp$iR`Pp>84Z9u2824t;0b>qh%mPKM*)V(~7)Py0&3Nj7T+I=%5sO(K z&hy7gHaY$y1Gsk<8{@9Q=hOa$sSF|Z8a}2;KJ9egc&*-8TW>b)W~+JQ-^;l_4W_f) z3no|i?Oe(**uZiG)S^|q6(5IhLr2eB#Y$Sld~+!RjscBwr$x%XJ@h4 z>mK$xZPD-dmTj@Rh5TJ;z!9t@tI$%&O z0AK^$O2Ecm0&9dp*I=O$A|PCs0_sw3S`4ns!7ognYp~F$%NaM#2RBdVrbFTC=`g=g z>5RJ?X(R@Sfv*f;?+4=G{eSv%|F4p0AO?tm)ntG-2L8ZwCE>tZ5 literal 0 HcmV?d00001 diff --git a/src/main/resources/i18n/messages/messages.properties b/src/main/resources/i18n/messages/messages.properties deleted file mode 100644 index 8cc6a276..00000000 --- a/src/main/resources/i18n/messages/messages.properties +++ /dev/null @@ -1,8 +0,0 @@ -system.error=An unexpected error has occurred. Please contact support -bad.request=Bad request -jaxb.node-element.empty=JAXB conversion error. Found {0} node -jaxb.parse=JAXB parsing error. {0} -redirect.session-id.not-blank=SessionID passed in request must be not-blank. - -error-code.PERSISTENCE_.title=Persistence error -error-code.PERSISTENCE_.detail=User with sessionId=[{0}] not found \ No newline at end of file diff --git a/src/main/resources/i18n/messages/messages_en.properties b/src/main/resources/i18n/messages_en.properties similarity index 100% rename from src/main/resources/i18n/messages/messages_en.properties rename to src/main/resources/i18n/messages_en.properties diff --git a/src/main/resources/i18n/messages/messages_it.properties b/src/main/resources/i18n/messages_it.properties similarity index 100% rename from src/main/resources/i18n/messages/messages_it.properties rename to src/main/resources/i18n/messages_it.properties From c1176ca154d2ad6c1ae599d7514e60a972a643f4 Mon Sep 17 00:00:00 2001 From: maxsca <130107847+maxsca@users.noreply.github.com> Date: Fri, 29 Mar 2024 18:58:30 +0100 Subject: [PATCH 4/5] NOD-784 upgrade wsdl generation --- .DS_Store | Bin 10244 -> 0 bytes .gitignore | 2 ++ src/main/.DS_Store | Bin 6148 -> 0 bytes src/main/resources/.DS_Store | Bin 8196 -> 0 bytes src/main/resources/i18n/.DS_Store | Bin 6148 -> 0 bytes 5 files changed, 2 insertions(+) delete mode 100644 .DS_Store delete mode 100644 src/main/.DS_Store delete mode 100644 src/main/resources/.DS_Store delete mode 100644 src/main/resources/i18n/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 7d93fd66fc0f6b37a369cd4d1f7e8e3e8c49b70b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMO=uHQ5S}$j)1pF@f2SU=^?mSOu&C z|AGSe&ZeVtqqg>H6|f3e1v~|4en{d;Hf3yGTQzmyMJ)l)M)9^f@H4IhR8G>^l(BVf zRVqGHuO1we>X;>lqtnr!q;Rw;W9!=LbZ~S!I0o4Ow0Ov0lCA9zfBVyHtwwak#@vTsIuIgevU?!Ee~wP5+2!_w60`2k;q#GfYo zE)Ty9HEIvIDtR2d9vsE_M1FX>1U!%PS~*hk`%e6*txMQz%aYa44EJ#^0QJcOFTH-E zayf$_zrfWmAJUa}x^i$uBFE+tnRz+(%%Z1*h-mhW;0S@QUxppnCtS$FC1g;Q47z%d zf$(zj{ob$&}_6ZPE9V?Kgcg}PZ4em z`(ha`KowfXMgL~$<=9V4X9w=QRc+7mIeKt}z}M}cQ1~^hJx?6e*l>|iFMi6wSj)Tx z-HXU-)f~=s`m)zfZR9oEZY_DDEvLf`_be!#XELhBJ*scH%av)huY2K^}T!V)z=m#9}R2Gm31bm&N$YX#kMG5y|u>w0*yC) z{DeP(bAK|&`jdDLXBi$P`6P%>1o>1UE0m3-9yL82fBEp&#$0LgIIiC-@Hz+%=iwUm z*(%NwIXNdpZw}sQ^>gf#eYbYpo>Oy`cm`(>7Q=Z&@78@hCNkA>(JklEVU|)9Vh^i; zRlq7>6<9|KM0Bl5+W*IWfUy7n*O4N&RI9-HQ^1L)GwDIBJM0G`?X@TIJdY3d Jr~D7=|3B~$E5!f+ diff --git a/.gitignore b/.gitignore index 79d7c43d..9754d5d8 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ hs_err_pid* # Helm /helm/charts/* **/.terraform/ + +.DS_Store \ No newline at end of file diff --git a/src/main/.DS_Store b/src/main/.DS_Store deleted file mode 100644 index ff84b25e97710375f587e147daf0458a422eb561..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z-O8Z74zx3gRi?wPLLv8oY#BU%-eSRBB>_24lA5#~ex_51=pPgZMno z>~6%;dhjA*XJGc5ou4fGZP*{i7$4;01IA3oSPK-fWK6;yA*{_uy-y*7+jTu-_m)G#!{gwXIzd9-_av;{X*e#bnsg;opDDYwZs51 zFwa0;bxl0~PrrZv&lgdT7$64z6$896bcX|&l0I7(CWmLO1$qmLf_bIF&k``?Q4G0w d6mNq{0l$R?prf%=2p$l+2uK>JAqIYxfe(8;P9FdO diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store deleted file mode 100644 index 0021aff2d41be8700b671eca8c53c71ef41bf080..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GLa6rOKe=&l=JTNWs#$kmHl3YAhYw19AXOT$mW*4~!>@Kg8RU0`LqTkr0@ z1#4sVkslxZi7{%TMiZ?siUy;;Xo3&=fDQh=@L+uMMNnUi#xpy6n-=J!hNL^m%$YOi zoSA#herF~#mobKP!Q8}HHDgSs%BiMObDP5DyxvlzXr!Dd$ev|K{gJHWWr@FZi*`H^ zM<9+s9Dz6jaRlNB+zAn&Gn*HAj&ol~<2H^!9D#Wm0lq&ZsB)T$=!Br*) z8B&7AZ5)9(0=Gthr%ySv*(TP^+?n_H?1*FgL1W`pNM+><7FJX!6>7!N%t>!F6Bt3k zPaFBeoa^yCCtK(MA^2IM?Xd$$;w@-x=8Om)Ym^SIHYL>-|Ds;Be09sZX>Y#A#I6I4(`i&Zdcwa zl4E^2&nXPMB&p09POd=8R;%M=>?ehGF7G)`m*?Ao?YRT}fpt3IGCt8PQU9Rt<%70x zvVNQ97g|+(jm{Bn>>sl7K2b%PT)d+8p8M)IZfV(>-qX=JwM46|QuSra`---2XB}(6 z@N<@H+U|+oQQHho4pL0rz&>tUc}1?o<2|l1Y)w^Zl}oDi8oj@ewVx>1!5LXg%Him0 zeT{m=Bu5T>+il-dBvg(mKT8Hg$*IpYw)?=_mV2B{qoRU9|EszVZRX4?0II zcY5(QyH}CR2@q(@TmG<)_$c*2vOqKRd=o*cobEi?cX~3wRDM;5EFCH}EDV@hLvT=eUe-F@>x64%cuUH}E_D zmMSD!Qlu(rsiaHGrFBxhv{~9AwM+Y@jQI6ZDWeY0_DV8|pWY)VqoOxH>HXVhRPCO< z`}TJnxMMTwhs8XHmQoI_NbtmJemFgiK>^wlPG_P&g#4^T2_YZi;U=t3Rj;gBRjb~; zX09CVrChO2%N+1pMWmfvD^sp$3nI2|9kCtSLc!KHJV;ob)TEGAYnwJJlzm!R#5Qat z7J^Z??@%ZYweqP|D{HEE)}~aA@qIuk&D2ga$^R9^zhYO|_XP1@3F7~t3^GA`!b7M_~R&0Oh+gyVKiO=l%KrFBGRtoB#j- diff --git a/src/main/resources/i18n/.DS_Store b/src/main/resources/i18n/.DS_Store deleted file mode 100644 index bde2e3734dee541cceb148b2949e341d5a8855ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z-O8O(;SR3gT(OYsFeUw0H@zzJL)usMN%S8ceg&wDwR6c>sMOAH?Tz zW_Ke>^d=%@rp$iR`Pp>84Z9u2824t;0b>qh%mPKM*)V(~7)Py0&3Nj7T+I=%5sO(K z&hy7gHaY$y1Gsk<8{@9Q=hOa$sSF|Z8a}2;KJ9egc&*-8TW>b)W~+JQ-^;l_4W_f) z3no|i?Oe(**uZiG)S^|q6(5IhLr2eB#Y$Sld~+!RjscBwr$x%XJ@h4 z>mK$xZPD-dmTj@Rh5TJ;z!9t@tI$%&O z0AK^$O2Ecm0&9dp*I=O$A|PCs0_sw3S`4ns!7ognYp~F$%NaM#2RBdVrbFTC=`g=g z>5RJ?X(R@Sfv*f;?+4=G{eSv%|F4p0AO?tm)ntG-2L8ZwCE>tZ5 From 2b3455f89ba92d6817f8abca3cb5592c45294b1a Mon Sep 17 00:00:00 2001 From: maxsca <130107847+maxsca@users.noreply.github.com> Date: Sat, 30 Mar 2024 22:38:17 +0100 Subject: [PATCH 5/5] NOD-784 upgrade wsdl generation --- .../wispconverter/config/WebMvcConfig.java | 1 - .../controller/RedirectController.java | 3 +- .../advice/GlobalExceptionHandler.java | 115 ++++++++---------- .../exception/AppClientException.java | 20 --- .../exception/AppErrorCodeMessageEnum.java | 21 ++-- .../wispconverter/exception/AppException.java | 24 ++-- .../wispconverter/service/CacheService.java | 8 +- .../service/ConverterService.java | 13 +- .../service/DebtPositionService.java | 4 +- .../service/NAVGeneratorService.java | 9 +- .../wispconverter/util/JaxbElementUtil.java | 16 ++- .../util/aspect/LoggingAspect.java | 54 ++++---- .../util/aspect/ResponseValidator.java | 2 +- src/main/resources/application.properties | 2 + .../resources/i18n/messages_en.properties | 30 +++-- .../resources/i18n/messages_it.properties | 28 +++-- 16 files changed, 171 insertions(+), 179 deletions(-) delete mode 100644 src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java diff --git a/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java b/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java index 45dec7ee..60f1c2a5 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java +++ b/src/main/java/it/gov/pagopa/wispconverter/config/WebMvcConfig.java @@ -55,7 +55,6 @@ public ResourceBundleMessageSource messageSource() { var resourceBundleMessageSource=new ResourceBundleMessageSource(); resourceBundleMessageSource.setBasename("i18n/messages"); // directory with messages_XX.properties resourceBundleMessageSource.setDefaultLocale(Locale.ENGLISH); - resourceBundleMessageSource.setUseCodeAsDefaultMessage(true); resourceBundleMessageSource.setDefaultEncoding(StandardCharsets.UTF_8.name()); resourceBundleMessageSource.setAlwaysUseMessageFormat(true); return resourceBundleMessageSource; diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/RedirectController.java b/src/main/java/it/gov/pagopa/wispconverter/controller/RedirectController.java index f7c4ed25..8062730e 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/RedirectController.java +++ b/src/main/java/it/gov/pagopa/wispconverter/controller/RedirectController.java @@ -37,7 +37,8 @@ public class RedirectController { }) @GetMapping public void redirect(@Parameter(description = "", example = "identificativoIntermediarioPA_sessionId") - @NotBlank(message = "{redirect.session-id.not-blank}") @RequestParam("sessionId") String sessionId, + @NotBlank(message = "{redirect.session-id.not-blank}") + @RequestParam("sessionId") String sessionId, HttpServletResponse response) throws IOException { ConversionResultDTO conversionResultDTO = converterService.convert(sessionId); response.sendRedirect(conversionResultDTO.getUri()); diff --git a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java index 9076e96d..9faf0bff 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java +++ b/src/main/java/it/gov/pagopa/wispconverter/controller/advice/GlobalExceptionHandler.java @@ -7,14 +7,21 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ProblemDetail; +import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.ErrorResponse; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import org.springframework.web.util.DefaultUriBuilderFactory; import java.net.URI; import java.time.Instant; @@ -27,92 +34,76 @@ @RequiredArgsConstructor public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + @Value("${error.code.uri}") + private String errorCodeUri; + private static final String ERROR_CODE_TITLE = "error-code.%s.title"; + private static final String ERROR_CODE_DETAIL = "error-code.%s.detail"; + private final MessageSource messageSource; @ExceptionHandler(AppException.class) public ErrorResponse handleAppException(AppException appEx) { - return ErrorResponse.builder(appEx, forAppErrorCodeMessageEnum(appEx.getError(), appEx.getReason())) - .typeMessageCode("https://pagopa.it/errors/"+getAppCode(appEx.getError())) - .titleMessageCode("error-code."+appEx.getError().name()+".title") - .detailMessageCode("error-code."+appEx.getError().name()+".detail") + return forAppException(appEx); + } + + @ExceptionHandler(Exception.class) + public ErrorResponse handleGenericException(Exception ex) { + String operationId = MDC.get(LoggingAspect.OPERATION_ID); + log.error(String.format("GenericException: operation-id=[%s]", operationId!=null?operationId:"n/a"), ex); + return forAppException(new AppException(ex, AppErrorCodeMessageEnum.ERROR, ex.getMessage())); + } + + @Override + protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatusCode statusCode, WebRequest request) { + if (body == null && ex instanceof ErrorResponse errorResponse) { + ProblemDetail problemDetail = errorResponse.updateAndGetBody(this.messageSource, LocaleContextHolder.getLocale()); + setExtraProperties(problemDetail); + body = problemDetail; + } + return super.handleExceptionInternal(ex, body, headers, statusCode, request); + } + + private ErrorResponse forAppException(AppException appEx){ + return ErrorResponse.builder(appEx, forAppErrorCodeMessageEnum(appEx.getError(), appEx.getMessage())) + .titleMessageCode(String.format(ERROR_CODE_TITLE, appEx.getError().name())) + .detailMessageCode(String.format(ERROR_CODE_DETAIL, appEx.getError().name())) .detailMessageArguments(appEx.getArgs()) .build(messageSource, LocaleContextHolder.getLocale()); } - private static ProblemDetail forAppErrorCodeMessageEnum(AppErrorCodeMessageEnum error, String reason) { + private ProblemDetail forAppErrorCodeMessageEnum(AppErrorCodeMessageEnum error, @Nullable String detail) { Assert.notNull(error, "AppErrorCodeMessageEnum is required"); ProblemDetail problemDetail = ProblemDetail.forStatus(error.getStatus()); - problemDetail.setType(URI.create("https://pagopa.it/errors/"+getAppCode(error))); + problemDetail.setType(getTypeFromErrorCode(getAppCode(error))); problemDetail.setTitle(error.getTitle()); - problemDetail.setDetail(reason); + problemDetail.setDetail(detail); - problemDetail.setProperty("timestamp", Instant.now()); problemDetail.setProperty("error-code", getAppCode(error)); + setExtraProperties(problemDetail); + + return problemDetail; + } + + private void setExtraProperties(ProblemDetail problemDetail){ + problemDetail.setProperty("timestamp", Instant.now()); String operationId = MDC.get(LoggingAspect.OPERATION_ID); if(operationId!=null){ problemDetail.setProperty("operation-id", operationId); } - return problemDetail; + } + private URI getTypeFromErrorCode(String errorCode) { + return new DefaultUriBuilderFactory() + .uriString(errorCodeUri) + .pathSegment(errorCode) + .build(); } - private static String getAppCode(AppErrorCodeMessageEnum error){ + private String getAppCode(AppErrorCodeMessageEnum error){ return String.format("%s-%s", Constants.SERVICE_CODE_APP, error.getCode()); } -// @ExceptionHandler(AppException.class) -// ProblemDetail handleAppException(AppException e) { -// Locale locale = LocaleContextHolder.getLocale(); -// String ff = messageSource.getMessage("error-code.PERSISTENCE_.title", Arrays.asList("ddd").toArray(), locale); -//// return e.getBody(); -// return e.getBody(); -// } -// -// private static ProblemDetail forAppException(AppException e) { -// Assert.notNull(e, "AppException is required"); -// AppErrorCodeMessageEnum error = e.getError(); -// -// ProblemDetail problemDetail = e.getBody(); -// problemDetail.setType(URI.create("https://pagopa.it/errors/"+getAppCode(error))); -// problemDetail.setTitle("error-code."+error.name()+".title"); -// problemDetail.setDetail("error-code."+error.name()+".detail"); -// problemDetail.setProperty("timestamp", Instant.now()); -// problemDetail.setProperty("error-code", getAppCode(error)); -// String operationId = MDC.get(OPERATION_ID); -// if(operationId!=null){ -// problemDetail.setProperty("operation-id", operationId); -// } -// return problemDetail; -// } -// -// private static String getAppCode(AppErrorCodeMessageEnum error){ -// return String.format("%s-%s", Constants.SERVICE_CODE_APP, error.getCode()); -// } - -// private ErrorResponse forAppClientException(AppClientException e) { -// Assert.notNull(e, "AppClientException is required"); -// AppErrorCodeMessageEnum codeMessage = e.getError(); -// -// ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(codeMessage.getStatus(), codeMessage.getReason()); -// problemDetail.setProperty("timestamp", Instant.now()); -// problemDetail.setProperty("client-error-code", String.format("%s-%s", Constants.SERVICE_CODE_APP, codeMessage.getCode())); -// -// Optional requestIdOpt = Optional.ofNullable(MDC.get(HEADER_REQUEST_ID)); -// requestIdOpt.ifPresent(requestId -> problemDetail.setProperty(HEADER_REQUEST_ID.toLowerCase(), requestId)); -// -// String errorId = UUID.randomUUID().toString(); -// problemDetail.setProperty("error-id", errorId); -// -// return ErrorResponse.builder(e, problemDetail) -// .detailMessageCode(codeMessage.getMessageDetailCode()) -// .detailMessageArguments(e.getArgs()) -// .build(messageSource, LocaleContextHolder.getLocale()); -// } - - - // private final AppErrorUtil appErrorUtil; -// private final MessageSource messageSource; // // @ApiResponses(value = { // @ApiResponse(responseCode = "500", description = "Internal Server Error", content = { diff --git a/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java b/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java deleted file mode 100644 index 158c691b..00000000 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppClientException.java +++ /dev/null @@ -1,20 +0,0 @@ -package it.gov.pagopa.wispconverter.exception; - -import lombok.Getter; - -import java.io.Serializable; - -@Getter -public class AppClientException extends AppException { - - private final int httpStatusCode; - - public AppClientException(int httpStatusCode, AppErrorCodeMessageEnum error, String reason, Object... args) { - super(error, reason, args); - this.httpStatusCode = httpStatusCode; - } - public AppClientException(Throwable cause, int httpStatusCode, AppErrorCodeMessageEnum error, String reason, Object... args) { - super(cause, error, reason, args); - this.httpStatusCode = httpStatusCode; - } -} diff --git a/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java b/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java index cd3050ce..fafabf9f 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppErrorCodeMessageEnum.java @@ -6,23 +6,24 @@ @Getter public enum AppErrorCodeMessageEnum { - UNKNOWN("0000", "Unknown error", HttpStatus.INTERNAL_SERVER_ERROR), - ERROR("0500", "System error", HttpStatus.INTERNAL_SERVER_ERROR), - BAD_REQUEST("0400", "Bad Request", HttpStatus.BAD_REQUEST), - PARSING_("1000", "a", HttpStatus.BAD_REQUEST), - PARSING_JAXB_EMPTY_NODE_ELEMENT("1001", "JAXB node element is empty", HttpStatus.BAD_REQUEST), - PARSING_JAXB_PARSE_ERROR("1002", "JAXB error during parse", HttpStatus.BAD_REQUEST), - PERSISTENCE_("2000", "Persistence error", HttpStatus.BAD_REQUEST), - CLIENT_("3000", "cvv", HttpStatus.BAD_REQUEST), + ERROR ( 500, "System error", "{0}", HttpStatus.INTERNAL_SERVER_ERROR), + PARSE_ERROR (1000, "Parse error", "Error while parsing: {0}", HttpStatus.BAD_REQUEST), + PRIMITIVE_NOT_VALID (1001, "Primitive not valid", "Primitive [{0}] not valid", HttpStatus.NOT_ACCEPTABLE), + RPT_NOT_FOUND (1002, "RPT not found", "RPT with sessionId [{0}] not found", HttpStatus.NOT_FOUND), + CLIENT_IUV_GENERATOR (1003, "IUVGeneratorClient error", "IUVGeneratorClient status [{0}] - {1}", HttpStatus.EXPECTATION_FAILED), + CLIENT_GPD (1004, "GPDClient error", "GPDClient status [{0}] - {1}", HttpStatus.EXPECTATION_FAILED), + CLIENT_DECOUPLER_CACHING(1005, "DecouplerCachingClient error", "DecouplerCachingClient status [{0}] - {1}",HttpStatus.EXPECTATION_FAILED), ; - private final String code; + private final Integer code; private final String title; + private final String detail; private final HttpStatusCode status; - AppErrorCodeMessageEnum(String code, String title, HttpStatus status) { + AppErrorCodeMessageEnum(Integer code, String title, String detail, HttpStatus status) { this.code = code; this.title = title; + this.detail = detail; this.status = status; } } 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 d0a3ac57..36244c9c 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java +++ b/src/main/java/it/gov/pagopa/wispconverter/exception/AppException.java @@ -1,30 +1,40 @@ package it.gov.pagopa.wispconverter.exception; import lombok.Getter; +import org.apache.commons.lang3.StringUtils; + +import java.text.MessageFormat; @Getter public class AppException extends RuntimeException { private final AppErrorCodeMessageEnum error; private final transient Object[] args; - private final String reason; +// private final String detail; - public AppException(AppErrorCodeMessageEnum error, String reason, Object... args) { - super(reason); + public AppException(AppErrorCodeMessageEnum error, Object... args) { + super(composeMessage(error, getArgsOrNull(args))); this.error = error; - this.reason = reason; this.args = getArgsOrNull(args); +// this.detail = composeMessage(error, getArgsOrNull(args)); } - public AppException(Throwable cause, AppErrorCodeMessageEnum error, String reason, Object... args) { - super(reason, cause); + public AppException(Throwable cause, AppErrorCodeMessageEnum error, Object... args) { + super(composeMessage(error, getArgsOrNull(args)), cause); this.error = error; - this.reason = reason; this.args = getArgsOrNull(args); +// this.detail = composeMessage(error, getArgsOrNull(args)); } private static Object[] getArgsOrNull(Object... args) { return args.length > 0 ? args.clone() : null; } + private static String composeMessage(AppErrorCodeMessageEnum error, Object[] args){ + if(error.getDetail() != null){ + return MessageFormat.format(error.getDetail(), args); + } + return null; + } + } \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/wispconverter/service/CacheService.java b/src/main/java/it/gov/pagopa/wispconverter/service/CacheService.java index 84676b8c..45e14f36 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/service/CacheService.java +++ b/src/main/java/it/gov/pagopa/wispconverter/service/CacheService.java @@ -3,7 +3,6 @@ import feign.FeignException; import io.lettuce.core.RedisException; import it.gov.pagopa.wispconverter.client.decoupler.DecouplerCachingClient; -import it.gov.pagopa.wispconverter.exception.AppClientException; import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; import it.gov.pagopa.wispconverter.exception.AppException; import it.gov.pagopa.wispconverter.repository.CacheRepository; @@ -34,7 +33,6 @@ public class CacheService { public void storeRequestMappingInCache(List rptContentDTOs, String sessionId) { try { - rptContentDTOs.forEach(e -> { String idIntermediarioPA = e.getIdIntermediarioPA(); String noticeNumber = e.getNoticeNumber(); @@ -46,12 +44,8 @@ public void storeRequestMappingInCache(List rptContentDTOs, Strin String requestIDForRTHandling = String.format(CACHING_KEY_TEMPLATE, idIntermediarioPA, noticeNumber); this.cacheRepository.insert(requestIDForRTHandling, sessionId, this.requestIDMappingTTL); }); - - } catch (FeignException e) { - throw new AppClientException(e, e.status(), AppErrorCodeMessageEnum.CLIENT_, e.getMessage()); - } catch (RedisException e) { - throw new AppException(e, AppErrorCodeMessageEnum.PERSISTENCE_, e.getMessage()); + throw new AppException(e, AppErrorCodeMessageEnum.CLIENT_DECOUPLER_CACHING, e.status(), e.getMessage()); } } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/service/ConverterService.java b/src/main/java/it/gov/pagopa/wispconverter/service/ConverterService.java index 3e0d85a6..1257d3d0 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/service/ConverterService.java +++ b/src/main/java/it/gov/pagopa/wispconverter/service/ConverterService.java @@ -1,7 +1,5 @@ package it.gov.pagopa.wispconverter.service; -import com.azure.cosmos.CosmosException; -import com.azure.spring.data.cosmos.exception.CosmosAccessException; import gov.telematici.pagamenti.ws.NodoInviaCarrelloRPT; import gov.telematici.pagamenti.ws.NodoInviaRPT; import gov.telematici.pagamenti.ws.ppthead.IntestazioneCarrelloPPT; @@ -90,12 +88,9 @@ private PaymentPosition mapRPTToDebtPosition(RPTRequestDTO rptRequestDTO, RPTCon } private RPTRequestEntity getRPTRequestEntity(String sessionId) { - try { - Optional optRPTReqEntity = this.rptRequestRepository.findById(sessionId); - return optRPTReqEntity.orElseThrow(() -> new AppException(AppErrorCodeMessageEnum.PERSISTENCE_, String.format("User with sessionId=[%s] not found", sessionId), sessionId)); - } catch (CosmosException | CosmosAccessException e) { - throw new AppException(e, AppErrorCodeMessageEnum.PERSISTENCE_, e.getMessage()); - } + Optional optRPTReqEntity = this.rptRequestRepository.findById(sessionId); + return optRPTReqEntity.orElseThrow(() -> new AppException(AppErrorCodeMessageEnum.RPT_NOT_FOUND, sessionId)); + // TODO RE } @@ -135,7 +130,7 @@ private List getRPTContentDTO(String primitive, String payload) t .build(); }).toList(); } - default -> throw new AppException(AppErrorCodeMessageEnum.PARSING_, String.format("Primitive [%S] not valid", primitive)); + default -> throw new AppException(AppErrorCodeMessageEnum.PRIMITIVE_NOT_VALID, primitive); } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/service/DebtPositionService.java b/src/main/java/it/gov/pagopa/wispconverter/service/DebtPositionService.java index e86c8e38..59b544ac 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/service/DebtPositionService.java +++ b/src/main/java/it/gov/pagopa/wispconverter/service/DebtPositionService.java @@ -4,8 +4,8 @@ import it.gov.pagopa.wispconverter.client.gpd.GPDClient; import it.gov.pagopa.wispconverter.client.gpd.model.MultiplePaymentPosition; import it.gov.pagopa.wispconverter.client.gpd.model.PaymentPosition; -import it.gov.pagopa.wispconverter.exception.AppClientException; import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; +import it.gov.pagopa.wispconverter.exception.AppException; import it.gov.pagopa.wispconverter.service.mapper.DebtPositionMapper; import it.gov.pagopa.wispconverter.service.model.RPTContentDTO; import lombok.RequiredArgsConstructor; @@ -43,7 +43,7 @@ public void executeBulkCreation(List rptContentDTOs) { }); } catch (FeignException e) { - throw new AppClientException(e, e.status(), AppErrorCodeMessageEnum.CLIENT_, e.getMessage()); + throw new AppException(e, AppErrorCodeMessageEnum.CLIENT_GPD, e.status(), e.getMessage()); } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/service/NAVGeneratorService.java b/src/main/java/it/gov/pagopa/wispconverter/service/NAVGeneratorService.java index 5a21acfb..23c16df2 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/service/NAVGeneratorService.java +++ b/src/main/java/it/gov/pagopa/wispconverter/service/NAVGeneratorService.java @@ -4,7 +4,6 @@ import it.gov.pagopa.wispconverter.client.iuvgenerator.IUVGeneratorClient; import it.gov.pagopa.wispconverter.client.iuvgenerator.model.IUVGeneratorRequest; import it.gov.pagopa.wispconverter.client.iuvgenerator.model.IUVGeneratorResponse; -import it.gov.pagopa.wispconverter.exception.AppClientException; import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; import it.gov.pagopa.wispconverter.exception.AppException; import lombok.RequiredArgsConstructor; @@ -35,13 +34,9 @@ public String getNAVCodeFromIUVGenerator(String creditorInstitutionCode) { String navCode; try { IUVGeneratorResponse response = this.iuvGeneratorClient.generate(creditorInstitutionCode, request); - if (response == null) { - throw new AppException(AppErrorCodeMessageEnum.CLIENT_, "IUVGeneratorResponse is null"); - } - navCode = response.getIuv(); + return response.getIuv(); } catch (FeignException e) { - throw new AppClientException(e, e.status(), AppErrorCodeMessageEnum.CLIENT_, e.getMessage()); + throw new AppException(e, AppErrorCodeMessageEnum.CLIENT_IUV_GENERATOR, e.status(), e.getMessage()); } - return navCode; } } diff --git a/src/main/java/it/gov/pagopa/wispconverter/util/JaxbElementUtil.java b/src/main/java/it/gov/pagopa/wispconverter/util/JaxbElementUtil.java index 2c2edb55..aa0111ae 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/util/JaxbElementUtil.java +++ b/src/main/java/it/gov/pagopa/wispconverter/util/JaxbElementUtil.java @@ -45,12 +45,11 @@ private Element convertToElement(InputSource is, String nameSpaceUri, String loc Document doc = db.parse(is); NodeList nodeList = doc.getElementsByTagNameNS(nameSpaceUri, localName); if (nodeList.getLength() == 0) { - throw new AppException(AppErrorCodeMessageEnum.PARSING_JAXB_EMPTY_NODE_ELEMENT, "NodeList must be > 0"); + throw new AppException(AppErrorCodeMessageEnum.PARSE_ERROR, "NodeList must be > 0"); } return (Element) nodeList.item(0); } catch (ParserConfigurationException | IOException | SAXException e) { - log.error("Errore durante il parsing", e); - throw new AppException(e, AppErrorCodeMessageEnum.PARSING_JAXB_PARSE_ERROR, e.getMessage()); + throw new AppException(e, AppErrorCodeMessageEnum.PARSE_ERROR, e.getMessage()); } } @@ -61,8 +60,7 @@ public T convertToBean(Element element, Class targetType) { JAXBElement jaxbElement = unmarshaller.unmarshal(element, targetType); return jaxbElement.getValue(); } catch (JAXBException e) { - log.error("Errore durante unmarshal", e); - throw new AppException(e, AppErrorCodeMessageEnum.PARSING_, e.getMessage()); + throw new AppException(e, AppErrorCodeMessageEnum.PARSE_ERROR, e.getMessage()); } } @@ -79,12 +77,12 @@ public Element convertToRPTElement(byte[] source) { public T getSoapHeader(Envelope envelope, Class targetType) { Header header = envelope.getHeader(); if (header == null) { - throw new AppException(AppErrorCodeMessageEnum.PARSING_, "header is null"); + throw new AppException(AppErrorCodeMessageEnum.PARSE_ERROR, "header is null"); } List list = header.getAny(); if (list == null || list.isEmpty()) { - throw new AppException(AppErrorCodeMessageEnum.PARSING_, "headerValue is null or is empty"); + throw new AppException(AppErrorCodeMessageEnum.PARSE_ERROR, "headerValue is null or is empty"); } Element element = (Element) list.get(0); return convertToBean(element, targetType); @@ -93,12 +91,12 @@ public T getSoapHeader(Envelope envelope, Class targetType) { public T getSoapBody(Envelope envelope, Class targetType) { Body body = envelope.getBody(); if (body == null) { - throw new AppException(AppErrorCodeMessageEnum.PARSING_, "body is null"); + throw new AppException(AppErrorCodeMessageEnum.PARSE_ERROR, "body is null"); } List list = body.getAny(); if (list == null || list.isEmpty()) { - throw new AppException(AppErrorCodeMessageEnum.PARSING_, "bodyValue is null or is empty"); + throw new AppException(AppErrorCodeMessageEnum.PARSE_ERROR, "bodyValue is null or is empty"); } Element element = (Element) list.get(0); return convertToBean(element, targetType); diff --git a/src/main/java/it/gov/pagopa/wispconverter/util/aspect/LoggingAspect.java b/src/main/java/it/gov/pagopa/wispconverter/util/aspect/LoggingAspect.java index 47f6e0ce..2a2612d5 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/util/aspect/LoggingAspect.java +++ b/src/main/java/it/gov/pagopa/wispconverter/util/aspect/LoggingAspect.java @@ -1,23 +1,19 @@ package it.gov.pagopa.wispconverter.util.aspect; -//import it.gov.pagopa.wispconverter.controller.advice.model.ApiErrorResponse; -import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum; import jakarta.annotation.PostConstruct; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.AfterReturning; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.CodeSignature; import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.web.ErrorResponse; import java.util.HashMap; import java.util.Map; @@ -57,17 +53,21 @@ public class LoggingAspect { @Value("${info.properties.environment}") private String environment; -// private static String getDetail(ResponseEntity result) { -// if (result != null && result.getBody() != null && result.getBody().getMessage() != null) { -// return result.getBody().getMessage(); -// } else return AppErrorCodeMessageEnum.UNKNOWN.getMessageDetail(); -// } -// -// private static String getTitle(ResponseEntity result) { -// if (result != null && result.getBody() != null && result.getBody().getAppErrorCode() != null) { -// return result.getBody().getAppErrorCode(); -// } else return AppErrorCodeMessageEnum.UNKNOWN.getMessageDetail(); -// } + private static String getDetail(ResponseEntity result) { + String detail; + if (result != null && result.getBody() != null && result.getBody().getBody().getDetail() != null) { + return result.getBody().getBody().getDetail(); + } + return null; + } + + private static String getTitle(ResponseEntity result) { + String title; + if (result != null && result.getBody() != null && result.getBody().getBody().getTitle() != null) { + return result.getBody().getBody().getTitle(); + } + return null; + } public static String getExecutionTime() { String startTime = MDC.get(START_TIME); @@ -139,16 +139,16 @@ public Object logApiInvocation(ProceedingJoinPoint joinPoint) throws Throwable { return result; } -// @AfterReturning(value = "execution(* *..exception.ErrorHandler.*(..))", returning = "result") -// public void trowingApiInvocation(JoinPoint joinPoint, ResponseEntity result) { -// MDC.put(STATUS, "KO"); -// MDC.put(CODE, String.valueOf(result.getStatusCode().value())); -// MDC.put(RESPONSE_TIME, getExecutionTime()); -// MDC.put(FAULT_CODE, getTitle(result)); -// MDC.put(FAULT_DETAIL, getDetail(result)); -// log.info("Failed API operation {} - error: {}", MDC.get(METHOD), result); -// MDC.clear(); -// } + @AfterReturning(value = "execution(* *..exception.ErrorHandler.*(..))", returning = "result") + public void trowingApiInvocation(JoinPoint joinPoint, ResponseEntity result) { + MDC.put(STATUS, "KO"); + MDC.put(CODE, String.valueOf(result.getStatusCode().value())); + MDC.put(RESPONSE_TIME, getExecutionTime()); + MDC.put(FAULT_CODE, getTitle(result)); + MDC.put(FAULT_DETAIL, getDetail(result)); + log.info("Failed API operation {} - error: {}", MDC.get(METHOD), result); + MDC.clear(); + } @Around(value = "repository() || service()") public Object logTrace(ProceedingJoinPoint joinPoint) throws Throwable { diff --git a/src/main/java/it/gov/pagopa/wispconverter/util/aspect/ResponseValidator.java b/src/main/java/it/gov/pagopa/wispconverter/util/aspect/ResponseValidator.java index b4716ad4..e7049034 100644 --- a/src/main/java/it/gov/pagopa/wispconverter/util/aspect/ResponseValidator.java +++ b/src/main/java/it/gov/pagopa/wispconverter/util/aspect/ResponseValidator.java @@ -45,7 +45,7 @@ private void validateResponse(ResponseEntity response) { sb.append(error.getPropertyPath()).append(" ").append(error.getMessage()).append(". "); } var msg = StringUtils.chop(sb.toString()); - throw new AppException(AppErrorCodeMessageEnum.ERROR, "Invalid response"); + throw new AppException(AppErrorCodeMessageEnum.ERROR, msg); } } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 634a6525..0fd3c566 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -64,3 +64,5 @@ client.decoupler-caching.subscription-key=${CLIENT_DECOUPLERCACHING_SUBKEY:none} wisp-converter.aux-digit=3 wisp-converter.segregation-code=48 wisp-converter.cached-requestid-mapping.ttl.minutes=${CACHED_REQUESTID_MAPPING_TTL_MINUTES:1440} + +error.code.uri=${ERROR_CODE_URI:https://pagopa.gov/error-code} diff --git a/src/main/resources/i18n/messages_en.properties b/src/main/resources/i18n/messages_en.properties index 8cc6a276..b3ef1a20 100644 --- a/src/main/resources/i18n/messages_en.properties +++ b/src/main/resources/i18n/messages_en.properties @@ -1,8 +1,22 @@ -system.error=An unexpected error has occurred. Please contact support -bad.request=Bad request -jaxb.node-element.empty=JAXB conversion error. Found {0} node -jaxb.parse=JAXB parsing error. {0} -redirect.session-id.not-blank=SessionID passed in request must be not-blank. - -error-code.PERSISTENCE_.title=Persistence error -error-code.PERSISTENCE_.detail=User with sessionId=[{0}] not found \ No newline at end of file +error-code.ERROR.title=System error +error-code.ERROR.detail=An unexpected error has occurred. Please contact support + +error-code.PARSE_ERROR.title=Parse error +error-code.PARSE_ERROR.detail=Error while parsing: {0} + +error-code.PRIMITIVE_NOT_VALID.title=Primitive not valid +error-code.PRIMITIVE_NOT_VALID.detail=Primitive [{0}] not valid + +error-code.RPT_NOT_FOUND.title=RPT not found +error-code.RPT_NOT_FOUND.detail=RPT with sessionId [{0}] not found + +error-code.CLIENT_IUV_GENERATOR.title=IUVGeneratorClient error +error-code.CLIENT_IUV_GENERATOR.detail=IUVGeneratorClient status [{0}] - {1} + +error-code.CLIENT_GPD.title=GPDClient error +error-code.CLIENT_GPD.detail=GPDClient status [{0}] - {1} + +error-code.CLIENT_DECOUPLER_CACHING.title=DecouplerCachingClient error +error-code.CLIENT_DECOUPLER_CACHING.detail=DecouplerCachingClient status [{0}] - {1} + + diff --git a/src/main/resources/i18n/messages_it.properties b/src/main/resources/i18n/messages_it.properties index 88e9f7b0..e4c8bd1f 100644 --- a/src/main/resources/i18n/messages_it.properties +++ b/src/main/resources/i18n/messages_it.properties @@ -1,8 +1,20 @@ -system.error=Si è verificato un errore imprevisto. Si prega di contattare l'assistenza -bad.request=Richiesta errata -jaxb.node-element.empty=Errore di conversione JAXB. Trovati {0} nodi -jaxb.parse=Errore di parsing JAXB. {0} -redirect.session-id.not-blank=Il SessionID passato nella richiesta deve essere una stringa non vuota. - -error-code.PERSISTENCE_.title=Persistence error -error-code.PERSISTENCE_.detail=User with sessionId=[{0}] not found \ No newline at end of file +error-code.ERROR.title=Errore del sistema +error-code.ERROR.detail=Si è verificato un errore imprevisto. Si prega di contattare l'assistenza + +error-code.PARSE_ERROR.title=Errore di lettura +error-code.PARSE_ERROR.detail=Errore durante la lettura: {0} + +error-code.PRIMITIVE_NOT_VALID.title=Primitiva non valida +error-code.PRIMITIVE_NOT_VALID.detail=Primitiva [{0}] non valida + +error-code.RPT_NOT_FOUND.title=RPT non trovata +error-code.RPT_NOT_FOUND.detail=RPT con sessionId [{0}] non trovata + +error-code.CLIENT_IUV_GENERATOR.title=Errore IUVGeneratorClient +error-code.CLIENT_IUV_GENERATOR.detail=IUVGeneratorClient status [{0}] - {1} + +error-code.CLIENT_GPD.title=Errore GPDClient +error-code.CLIENT_GPD.detail=GPDClient status [{0}] - {1} + +error-code.CLIENT_DECOUPLER_CACHING.title=Errore DecouplerCachingClient +error-code.CLIENT_DECOUPLER_CACHING.detail=DecouplerCachingClient status [{0}] - {1} \ No newline at end of file