Fix synchronization issues in policy-api
[policy/api.git] / main / src / main / java / org / onap / policy / api / main / rest / CommonRestController.java
1 /*-\r
2  * ============LICENSE_START=======================================================\r
3  * ONAP Policy API\r
4  * ================================================================================\r
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.\r
6  * Modifications Copyright (C) 2022 Bell Canada. All rights reserved.\r
7  * Modifications Copyright (C) 2022-2023 Nordix Foundation.\r
8  * ================================================================================\r
9  * Licensed under the Apache License, Version 2.0 (the "License");\r
10  * you may not use this file except in compliance with the License.\r
11  * You may obtain a copy of the License at\r
12  *\r
13  *      http://www.apache.org/licenses/LICENSE-2.0\r
14  *\r
15  * Unless required by applicable law or agreed to in writing, software\r
16  * distributed under the License is distributed on an "AS IS" BASIS,\r
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
18  * See the License for the specific language governing permissions and\r
19  * limitations under the License.\r
20  *\r
21  * SPDX-License-Identifier: Apache-2.0\r
22  * ============LICENSE_END=========================================================\r
23  */\r
24 \r
25 package org.onap.policy.api.main.rest;\r
26 \r
27 import java.util.Objects;\r
28 import java.util.UUID;\r
29 import java.util.concurrent.Semaphore;\r
30 import org.onap.policy.api.main.exception.PolicyApiRuntimeException;\r
31 import org.onap.policy.common.utils.coder.Coder;\r
32 import org.onap.policy.common.utils.coder.CoderException;\r
33 import org.onap.policy.common.utils.coder.StandardCoder;\r
34 import org.slf4j.Logger;\r
35 import org.slf4j.LoggerFactory;\r
36 import org.springframework.http.HttpStatus;\r
37 import org.springframework.http.ResponseEntity;\r
38 import org.springframework.web.bind.annotation.ExceptionHandler;\r
39 import org.springframework.web.context.request.WebRequest;\r
40 \r
41 /**\r
42  * Super class from which REST controllers are derived.\r
43  */\r
44 public class CommonRestController {\r
45 \r
46     protected static Semaphore mutex = new Semaphore(1);\r
47 \r
48     private static final Logger LOGGER = LoggerFactory.getLogger(CommonRestController.class);\r
49 \r
50     protected static final String EXTENSION_NAME = "interface info";\r
51 \r
52     protected static final String API_VERSION_NAME = "api-version";\r
53     protected static final String API_VERSION = "1.0.0";\r
54 \r
55     protected static final String LAST_MOD_NAME = "last-mod-release";\r
56 \r
57     protected static final String AUTHORIZATION_TYPE = "basicAuth";\r
58 \r
59     protected static final String VERSION_MINOR_NAME = "X-MinorVersion";\r
60     protected static final String VERSION_MINOR_DESCRIPTION =\r
61         "Used to request or communicate a MINOR version back from the client"\r
62             + " to the server, and from the server back to the client";\r
63 \r
64     protected static final String VERSION_PATCH_NAME = "X-PatchVersion";\r
65     protected static final String VERSION_PATCH_DESCRIPTION = "Used only to communicate a PATCH version in a "\r
66         + "response for troubleshooting purposes only, and will not be provided by" + " the client on request";\r
67 \r
68     protected static final String VERSION_LATEST_NAME = "X-LatestVersion";\r
69     protected static final String VERSION_LATEST_DESCRIPTION = "Used only to communicate an API's latest version";\r
70 \r
71     public static final String REQUEST_ID_NAME = "X-ONAP-RequestID";\r
72     protected static final String REQUEST_ID_HDR_DESCRIPTION = "Used to track REST transactions for logging purpose";\r
73     protected static final String REQUEST_ID_PARAM_DESCRIPTION = "RequestID for http transaction";\r
74 \r
75     protected static final String AUTHENTICATION_ERROR_MESSAGE = "Authentication Error";\r
76     protected static final String AUTHORIZATION_ERROR_MESSAGE = "Authorization Error";\r
77     protected static final String SERVER_ERROR_MESSAGE = "Internal Server Error";\r
78     protected static final String NOT_FOUND_MESSAGE = "Resource Not Found";\r
79     protected static final String INVALID_BODY_MESSAGE = "Invalid Body";\r
80     protected static final String INVALID_PAYLOAD_MESSAGE = "Not Acceptable Payload";\r
81     protected static final String HTTP_CONFLICT_MESSAGE = "Delete Conflict, Rule Violation";\r
82     protected static final String ERROR_MESSAGE_NO_POLICIES_FOUND = "No policies found";\r
83 \r
84     protected final Coder coder = new StandardCoder();\r
85 \r
86     protected <T> ResponseEntity<T> makeOkResponse(UUID requestId, T respEntity) {\r
87         return makeResponse(requestId, respEntity, HttpStatus.OK.value());\r
88     }\r
89 \r
90     protected <T> ResponseEntity<T> makeResponse(UUID requestId, T respEntity, int status) {\r
91         return CommonRestController\r
92             .addLoggingHeaders(addVersionControlHeaders(ResponseEntity.status(status)), requestId)\r
93             .body(respEntity);\r
94     }\r
95 \r
96     /**\r
97      * Adds version headers to the response.\r
98      *\r
99      * @param respBuilder response builder\r
100      * @return the response builder, with version headers\r
101      */\r
102     public static ResponseEntity.BodyBuilder addVersionControlHeaders(ResponseEntity.BodyBuilder respBuilder) {\r
103         return respBuilder.header(VERSION_MINOR_NAME, "0").header(VERSION_PATCH_NAME, "0").header(VERSION_LATEST_NAME,\r
104             API_VERSION);\r
105     }\r
106 \r
107     /**\r
108      * Adds logging headers to the response.\r
109      *\r
110      * @param respBuilder response builder\r
111      * @return the response builder, with version logging\r
112      */\r
113     public static ResponseEntity.BodyBuilder addLoggingHeaders(ResponseEntity.BodyBuilder respBuilder, UUID requestId) {\r
114         // Generate a random uuid if client does not embed requestId in rest request\r
115         return respBuilder.header(REQUEST_ID_NAME,\r
116             Objects.requireNonNullElseGet(requestId, UUID::randomUUID).toString());\r
117 \r
118     }\r
119 \r
120     /**\r
121      * Converts an object to a JSON string.\r
122      *\r
123      * @param object object to convert\r
124      * @return a JSON string representing the object\r
125      */\r
126     protected String toJson(Object object) {\r
127         if (object == null) {\r
128             return null;\r
129         }\r
130 \r
131         try {\r
132             return coder.encode(object);\r
133 \r
134         } catch (CoderException e) {\r
135             LOGGER.warn("cannot convert {} to JSON", object.getClass().getName(), e);\r
136             return null;\r
137         }\r
138     }\r
139 \r
140     @ExceptionHandler(value = {PolicyApiRuntimeException.class})\r
141     protected ResponseEntity<Object> handleException(PolicyApiRuntimeException ex, WebRequest req) {\r
142         LOGGER.warn(ex.getMessage(), ex.getCause());\r
143         final var requestId = req.getHeader(CommonRestController.REQUEST_ID_NAME);\r
144         final var status = ex.getErrorResponse().getResponseCode().getStatusCode();\r
145         return CommonRestController.addLoggingHeaders(\r
146             CommonRestController.addVersionControlHeaders(ResponseEntity.status(status)),\r
147             requestId != null ? UUID.fromString(requestId) : ex.getRequestId()).body(ex.getErrorResponse());\r
148     }\r
149 }\r