From 411a7aa191a48170336dfa0fc5c44a17f99fd186 Mon Sep 17 00:00:00 2001 From: "a.sreekumar" Date: Mon, 14 Feb 2022 11:11:11 +0000 Subject: Fix swagger and improve exception handling 1) Swagger was getting generated in a different format due to a serialization isue. It is fixed. 2) Improved exception handling by taking care of any exceptions that could occur in and around database operations. 3) AAF enabling/disabling was done using spring profiles. This is changed to using parameters, as it is more easier to configure in an OOM helm chart deployment Change-Id: If1bee01379ba5c4efac29822662896d8aa883fc8 Issue-ID: POLICY-3975 Signed-off-by: a.sreekumar --- .../onap/policy/pap/main/PapExceptionHandler.java | 85 ---------------------- .../onap/policy/pap/main/PolicyPapApplication.java | 14 +++- .../onap/policy/pap/main/config/PapAafConfig.java | 6 +- .../main/exception/ControllerExceptionHandler.java | 85 ++++++++++++++++++++++ .../main/exception/ServiceExceptionHandler.java | 64 ++++++++++++++++ main/src/main/resources/application.yaml | 1 + .../policy/pap/main/rest/CommonPapRestServer.java | 4 +- main/src/test/resources/config/application.yaml | 1 + .../src/main/resources/etc/papParameters.yaml | 1 + 9 files changed, 170 insertions(+), 91 deletions(-) delete mode 100644 main/src/main/java/org/onap/policy/pap/main/PapExceptionHandler.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/exception/ControllerExceptionHandler.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/exception/ServiceExceptionHandler.java diff --git a/main/src/main/java/org/onap/policy/pap/main/PapExceptionHandler.java b/main/src/main/java/org/onap/policy/pap/main/PapExceptionHandler.java deleted file mode 100644 index 54418123..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/PapExceptionHandler.java +++ /dev/null @@ -1,85 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2021 Bell Canada. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.pap.main; - -import java.util.UUID; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; -import org.onap.policy.models.errors.concepts.ErrorResponse; -import org.onap.policy.pap.main.rest.PapRestControllerV1; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.context.request.WebRequest; - -@RestControllerAdvice -public class PapExceptionHandler { - - private static final Logger logger = LoggerFactory.getLogger(PapExceptionHandler.class); - - /** - * Handle PfModelException. - * - * @return ResponseEntity the response - */ - @ExceptionHandler(PfModelException.class) - public ResponseEntity pfModelExceptionHandler(PfModelException exp, WebRequest req) { - return handlePfModelException(exp, exp.getErrorResponse(), req); - } - - /** - * Handle PfModelRuntimeException. - * - * @return ResponseEntity the response - */ - @ExceptionHandler(PfModelRuntimeException.class) - public ResponseEntity pfModelRuntimeExceptionHandler(PfModelRuntimeException exp, WebRequest req) { - return handlePfModelException(exp, exp.getErrorResponse(), req); - } - - private ResponseEntity handlePfModelException(Exception exp, ErrorResponse errorResponse, - WebRequest req) { - logger.warn(exp.getMessage(), exp); - String requestId = req.getHeader(PapRestControllerV1.REQUEST_ID_NAME); - return PapRestControllerV1.addLoggingHeaders( - PapRestControllerV1 - .addVersionControlHeaders(ResponseEntity.status(errorResponse.getResponseCode().getStatusCode())), - requestId != null ? UUID.fromString(requestId) : null).body(errorResponse); - } - - /** - * Handle IllegalArgumentException. - * - * @return ResponseEntity the response - */ - @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity handleIllegalArgumentException(IllegalArgumentException exp, WebRequest req) { - String errorMessage = exp.getClass().getName() + " " + exp.getMessage(); - logger.warn(exp.getMessage(), exp); - String requestId = req.getHeader(PapRestControllerV1.REQUEST_ID_NAME); - return PapRestControllerV1.addLoggingHeaders( - PapRestControllerV1.addVersionControlHeaders(ResponseEntity.status(HttpStatus.BAD_REQUEST)), - requestId != null ? UUID.fromString(requestId) : null).body(errorMessage); - } -} diff --git a/main/src/main/java/org/onap/policy/pap/main/PolicyPapApplication.java b/main/src/main/java/org/onap/policy/pap/main/PolicyPapApplication.java index ede40126..edb6ff6d 100644 --- a/main/src/main/java/org/onap/policy/pap/main/PolicyPapApplication.java +++ b/main/src/main/java/org/onap/policy/pap/main/PolicyPapApplication.java @@ -22,12 +22,15 @@ package org.onap.policy.pap.main; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonParser; +import com.google.gson.JsonSerializer; import org.onap.policy.common.gson.GsonMessageBodyHandler; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.context.annotation.Bean; +import springfox.documentation.spring.web.json.Json; @SpringBootApplication(exclude = {JacksonAutoConfiguration.class}) @EntityScan( @@ -39,8 +42,17 @@ public class PolicyPapApplication { SpringApplication.run(PolicyPapApplication.class, args); } + /** + * Configure gson with the required adapters to be used in the application. + * + * @return the gson bean + */ @Bean public Gson gson() { - return GsonMessageBodyHandler.configBuilder(new GsonBuilder()).create(); + GsonBuilder gsonBuilder = GsonMessageBodyHandler.configBuilder(new GsonBuilder()); + JsonSerializer serializer = + (json, type, jsonSerializationContext) -> JsonParser.parseString(json.value()); + gsonBuilder.registerTypeAdapter(Json.class, serializer); + return gsonBuilder.create(); } } diff --git a/main/src/main/java/org/onap/policy/pap/main/config/PapAafConfig.java b/main/src/main/java/org/onap/policy/pap/main/config/PapAafConfig.java index d73a37d8..4bbf29f6 100644 --- a/main/src/main/java/org/onap/policy/pap/main/config/PapAafConfig.java +++ b/main/src/main/java/org/onap/policy/pap/main/config/PapAafConfig.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021 Bell Canada. All rights reserved. + * Copyright (C) 2021-2022 Bell Canada. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,12 +22,12 @@ package org.onap.policy.pap.main.config; import javax.servlet.Filter; import org.onap.policy.pap.main.rest.PapAafFilter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; @Configuration -@Profile(value = {"aaf-auth"}) +@ConditionalOnProperty(value = "pap.aaf", havingValue = "true") public class PapAafConfig { /** diff --git a/main/src/main/java/org/onap/policy/pap/main/exception/ControllerExceptionHandler.java b/main/src/main/java/org/onap/policy/pap/main/exception/ControllerExceptionHandler.java new file mode 100644 index 00000000..2b4217c0 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/exception/ControllerExceptionHandler.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Bell Canada. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pap.main.exception; + +import java.util.UUID; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.errors.concepts.ErrorResponse; +import org.onap.policy.pap.main.rest.PapRestControllerV1; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; + +@RestControllerAdvice +public class ControllerExceptionHandler { + + private static final Logger logger = LoggerFactory.getLogger(ControllerExceptionHandler.class); + + /** + * Handle PfModelException. + * + * @return ResponseEntity the response + */ + @ExceptionHandler(PfModelException.class) + public ResponseEntity pfModelExceptionHandler(PfModelException exp, WebRequest req) { + return handlePfModelException(exp, exp.getErrorResponse(), req); + } + + /** + * Handle PfModelRuntimeException. + * + * @return ResponseEntity the response + */ + @ExceptionHandler(PfModelRuntimeException.class) + public ResponseEntity pfModelRuntimeExceptionHandler(PfModelRuntimeException exp, WebRequest req) { + return handlePfModelException(exp, exp.getErrorResponse(), req); + } + + private ResponseEntity handlePfModelException(Exception exp, ErrorResponse errorResponse, + WebRequest req) { + logger.warn(exp.getMessage(), exp); + String requestId = req.getHeader(PapRestControllerV1.REQUEST_ID_NAME); + return PapRestControllerV1.addLoggingHeaders( + PapRestControllerV1 + .addVersionControlHeaders(ResponseEntity.status(errorResponse.getResponseCode().getStatusCode())), + requestId != null ? UUID.fromString(requestId) : null).body(errorResponse); + } + + /** + * Handle IllegalArgumentException. + * + * @return ResponseEntity the response + */ + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity handleIllegalArgumentException(IllegalArgumentException exp, WebRequest req) { + String errorMessage = exp.getClass().getName() + " " + exp.getMessage(); + logger.warn(exp.getMessage(), exp); + String requestId = req.getHeader(PapRestControllerV1.REQUEST_ID_NAME); + return PapRestControllerV1.addLoggingHeaders( + PapRestControllerV1.addVersionControlHeaders(ResponseEntity.status(HttpStatus.BAD_REQUEST)), + requestId != null ? UUID.fromString(requestId) : null).body(errorMessage); + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/exception/ServiceExceptionHandler.java b/main/src/main/java/org/onap/policy/pap/main/exception/ServiceExceptionHandler.java new file mode 100644 index 00000000..80887961 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/exception/ServiceExceptionHandler.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Bell Canada. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pap.main.exception; + +import javax.ws.rs.core.Response; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.springframework.stereotype.Component; +import org.springframework.transaction.TransactionException; + +@Aspect +@Component +public class ServiceExceptionHandler { + + /** + * Handle any exceptions that are not already handled. + * For e.g., runtime exceptions that could happen during SQL query execution related to data integrity etc. + * + * @param joinPoint the point of execution + * @param exception the exception + */ + @AfterThrowing(pointcut = "execution(* org.onap.policy.pap.main.service.*.*(..))", throwing = "exception") + public void handleServiceException(JoinPoint joinPoint, RuntimeException exception) { + if (exception instanceof PfModelRuntimeException) { + throw (PfModelRuntimeException) exception; + } else { + throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, exception.getMessage(), exception); + } + } + + /** + * Handle DB Transaction related exceptions. + * All service classes in org.onap.policy.pap.main.service are transactional now, + * Autowiring these service classes can cause TransactionException. + * For e.g., JDBC connection failure occurs and failed to open transaction at service level + * + * @param joinPoint the point of execution + * @param exception the exception + */ + @AfterThrowing(pointcut = "execution(* org.onap.policy.pap.main.*.*.*(..))", throwing = "exception") + public void handleTransactionException(JoinPoint joinPoint, TransactionException exception) { + throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, exception.getMessage(), exception); + } +} diff --git a/main/src/main/resources/application.yaml b/main/src/main/resources/application.yaml index 2b6d8fc8..ebe94b89 100644 --- a/main/src/main/resources/application.yaml +++ b/main/src/main/resources/application.yaml @@ -26,6 +26,7 @@ server: pap: name: PapGroup + aaf: false pdpParameters: heartBeatMs: 120000 updateParameters: diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java b/main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java index c2d9f038..fd4bb742 100644 --- a/main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java +++ b/main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java @@ -51,11 +51,11 @@ import org.onap.policy.common.gson.GsonMessageBodyHandler; import org.onap.policy.common.utils.network.NetworkUtil; import org.onap.policy.common.utils.security.SelfSignedKeyStore; import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.pap.main.PapConstants; import org.onap.policy.pap.main.PolicyPapApplication; import org.onap.policy.pap.main.parameters.CommonTestData; import org.onap.policy.pap.main.startstop.PapActivator; import org.powermock.reflect.Whitebox; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.annotation.DirtiesContext; @@ -91,7 +91,6 @@ public abstract class CommonPapRestServer { @LocalServerPort private int port; - @Autowired private PapActivator papActivator; /** @@ -126,6 +125,7 @@ public abstract class CommonPapRestServer { @Before public void setUp() throws Exception { httpsPrefix = "https://localhost:" + port + "/"; + papActivator = Registry.get(PapConstants.REG_PAP_ACTIVATOR, PapActivator.class); activatorWasAlive = papActivator.isAlive(); } diff --git a/main/src/test/resources/config/application.yaml b/main/src/test/resources/config/application.yaml index b6a497ac..2fb9514d 100644 --- a/main/src/test/resources/config/application.yaml +++ b/main/src/test/resources/config/application.yaml @@ -24,6 +24,7 @@ server: pap: name: "PapGroup" + aaf: false pdpParameters: updateParameters: maxRetryCount: 1 diff --git a/packages/policy-pap-tarball/src/main/resources/etc/papParameters.yaml b/packages/policy-pap-tarball/src/main/resources/etc/papParameters.yaml index 0c37b468..06dd45f4 100644 --- a/packages/policy-pap-tarball/src/main/resources/etc/papParameters.yaml +++ b/packages/policy-pap-tarball/src/main/resources/etc/papParameters.yaml @@ -28,6 +28,7 @@ server: pap: name: PapGroup + aaf: false pdpParameters: heartBeatMs: 120000 updateParameters: -- cgit 1.2.3-korg