Merge the POMBA code to ONAP AAI data router
[aai/data-router.git] / src / main / java / org / onap / aai / datarouter / service / AuditService.java
1 /**\r
2  * ============LICENSE_START=======================================================\r
3  * org.onap.aai\r
4  * ================================================================================\r
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.\r
6  * Copyright © 2017-2018 Amdocs\r
7  * ================================================================================\r
8  * Licensed under the Apache License, Version 2.0 (the "License");\r
9  * you may not use this file except in compliance with the License.\r
10  * You may obtain a copy of the License at\r
11  *\r
12  *       http://www.apache.org/licenses/LICENSE-2.0\r
13  *\r
14  * Unless required by applicable law or agreed to in writing, software\r
15  * distributed under the License is distributed on an "AS IS" BASIS,\r
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
17  * See the License for the specific language governing permissions and\r
18  * limitations under the License.\r
19  * ============LICENSE_END=========================================================\r
20  */\r
21 package org.onap.aai.datarouter.service;\r
22 \r
23 import java.util.ArrayList;\r
24 import java.util.HashMap;\r
25 import java.util.List;\r
26 import java.util.Map;\r
27 import java.util.UUID;\r
28 import javax.servlet.http.HttpServletRequest;\r
29 import javax.ws.rs.Consumes;\r
30 import javax.ws.rs.Encoded;\r
31 import javax.ws.rs.POST;\r
32 import javax.ws.rs.Path;\r
33 import javax.ws.rs.PathParam;\r
34 import javax.ws.rs.Produces;\r
35 import javax.ws.rs.core.Context;\r
36 import javax.ws.rs.core.HttpHeaders;\r
37 import javax.ws.rs.core.MediaType;\r
38 import javax.ws.rs.core.Response;\r
39 import javax.ws.rs.core.Response.Status;\r
40 import javax.ws.rs.core.UriInfo;\r
41 import org.onap.aai.cl.api.Logger;\r
42 import org.onap.aai.cl.eelf.LoggerFactory;\r
43 import org.onap.aai.cl.mdc.MdcContext;\r
44 import org.onap.aai.datarouter.entity.POAAuditEvent;\r
45 import org.onap.aai.datarouter.entity.POAServiceInstanceEntity;\r
46 import org.onap.aai.datarouter.exception.POAAuditException;\r
47 import org.onap.aai.datarouter.logging.DataRouterMsgs;\r
48 import org.onap.aai.datarouter.util.LoggingUtil;\r
49 import org.onap.aai.event.api.EventPublisher;\r
50 import org.onap.aai.datarouter.util.DataRouterConstants;\r
51 import org.onap.aai.restclient.client.Headers;\r
52 \r
53 \r
54 \r
55 public class AuditService {\r
56 \r
57     private static Logger logger = LoggerFactory.getInstance().getLogger(AuditService.class.getName());\r
58     private static Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(AuditService.class.getName());\r
59 \r
60     private static final String MEDIA_TYPE = MediaType.APPLICATION_JSON;\r
61     private static final String DATA_ROUTER_APP = "Data-Router";\r
62     private static final String UNKNOWN_APP = "[unknown_app_id]";\r
63     private static final String RESULT_OK = "200 OK";\r
64 \r
65     private EventPublisher publisher;\r
66 \r
67     public AuditService(EventPublisher publisher) throws Exception {\r
68         this.publisher = publisher;\r
69     }\r
70 \r
71 \r
72     /**\r
73      * Handles an incoming post-orchestration audit request.\r
74      * Generates and posts audit events to DMaaP.\r
75      *\r
76      * @param content - JSON structure containing the request payload\r
77      * @param uri     - Http request uri\r
78      * @param headers - Http request headers\r
79      * @param uriInfo - Http URI info field\r
80      * @param req     - Http request structure.\r
81      * @return - Standard HTTP response.\r
82      *\r
83      */\r
84     @POST\r
85     @Path("/orchestration-event/")\r
86     @Consumes({MediaType.APPLICATION_JSON})\r
87     @Produces({MediaType.APPLICATION_JSON})\r
88     public Response triggerPOA(String content,\r
89             @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,\r
90             @Context HttpServletRequest req) {\r
91 \r
92         logger.debug("Incoming request..." + content);\r
93         Response response = null;\r
94         try {\r
95             Map<String, String> headerAttributes = initializeLogging(req, headers);\r
96 \r
97             List<String> serviceInstanceEvents = generateServiceInstanceEvents(headerAttributes, content);\r
98             processEvent(serviceInstanceEvents);\r
99 \r
100             response = Response.status(Status.OK).entity(RESULT_OK).type(MEDIA_TYPE).build();\r
101             LoggingUtil.logRestRequest(logger, auditLogger, req, response);\r
102 \r
103         } catch(POAAuditException e) {\r
104             response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();\r
105             LoggingUtil.logRestRequest(logger, auditLogger, req, response, e);\r
106         } finally {\r
107             LoggingUtil.closeMdc();\r
108         }\r
109         return response;\r
110     }\r
111 \r
112 \r
113     /**\r
114      * Initialize MDC logging using attributes from the request\r
115      * @param httpReq\r
116      * @param httpHeaders\r
117      * @return Returns a map of required header attributes\r
118      * @throws POAAuditException\r
119      */\r
120     private Map<String, String> initializeLogging(HttpServletRequest httpReq, HttpHeaders httpHeaders) throws POAAuditException {\r
121 \r
122         Map<String, String> headers = new HashMap<String, String>();\r
123         String remoteAddr = httpReq.getRemoteAddr();\r
124 \r
125         if (httpHeaders.getRequestHeaders() == null) {\r
126             String error="Missing Header";\r
127             throw new POAAuditException(error, Status.BAD_REQUEST, DataRouterMsgs.BAD_REST_REQUEST, error);\r
128         }\r
129         String transactionId = httpHeaders.getRequestHeaders().getFirst(Headers.TRANSACTION_ID);\r
130         if((transactionId == null) || transactionId.trim().isEmpty()) {\r
131             transactionId = UUID.randomUUID().toString();\r
132             logger.debug("Header " + Headers.TRANSACTION_ID + "not present in request, generating new value: " + transactionId);\r
133         }\r
134         headers.put(Headers.TRANSACTION_ID, transactionId);\r
135 \r
136         String fromAppId = httpHeaders.getRequestHeaders().getFirst(Headers.FROM_APP_ID);\r
137         if((fromAppId == null) || fromAppId.trim().isEmpty()) {\r
138             // initialize the context before throwing the exception\r
139             MdcContext.initialize(transactionId, DataRouterConstants.DATA_ROUTER_SERVICE_NAME, "", UNKNOWN_APP, remoteAddr);\r
140             String error = "Missing header attribute: " + Headers.FROM_APP_ID;\r
141             throw new POAAuditException(error, Status.BAD_REQUEST, DataRouterMsgs.BAD_REST_REQUEST, error);\r
142         }\r
143         headers.put(Headers.FROM_APP_ID, fromAppId);\r
144 \r
145         LoggingUtil.initMdc(transactionId, fromAppId, remoteAddr);\r
146 \r
147         return headers;\r
148     }\r
149 \r
150 \r
151 \r
152     /**\r
153      * Extracts service instances and generates a list of events\r
154      * @param eventHeaders\r
155      * @param requestBody\r
156      * @return Returns a list of service instances\r
157      * @throws POAAuditException if the request contains errors\r
158      */\r
159     private List<String> generateServiceInstanceEvents(Map<String, String> eventHeaders, String requestBody) throws POAAuditException {\r
160 \r
161         POAAuditEvent auditEvent = POAAuditEvent.fromJson(requestBody);\r
162         auditEvent.validate();\r
163 \r
164         List<String> eventMessages = new ArrayList<String>();\r
165         for (POAServiceInstanceEntity serviceInstance: auditEvent.getServiceInstanceList()) {\r
166             serviceInstance.validate();\r
167             serviceInstance.setxFromAppId(DATA_ROUTER_APP);\r
168             serviceInstance.setxTransactionId(eventHeaders.get(Headers.TRANSACTION_ID));\r
169             eventMessages.add(serviceInstance.toJson());\r
170         }\r
171         return eventMessages;\r
172     }\r
173 \r
174 \r
175     /**\r
176      * Publish events to DMaaP.\r
177      * @param eventMessages\r
178      * @throws POAAuditException\r
179      *\r
180      * Note: The Default Transport Type in the DMaaPEventPublisher is defined as "HTTPAAF". Based on the deployment of DMaap, currently\r
181      * by default the "HTTPAUTH" transport type is supported.\r
182      */\r
183     private void processEvent(List<String> eventMessages) throws POAAuditException {\r
184 \r
185         int messagesSent = 0;\r
186         try {\r
187             messagesSent = publisher.sendSync(eventMessages);\r
188             logger.debug("The number of messages successfully sent: "+ messagesSent);\r
189 \r
190             if (messagesSent > 0) {\r
191                 logger.debug("Published Message: " + eventMessages);\r
192             } else {\r
193                 String exceptionStr = String.format("Failed to publish %d event(s) to DMaaP", eventMessages.size());\r
194                 logger.debug(exceptionStr);\r
195             }\r
196 \r
197 \r
198         } catch (Exception e) {\r
199             throw new POAAuditException("Failed to publish event to DMaaP: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR,\r
200                     DataRouterMsgs.EXCEPTION_DURING_METHOD_CALL, e.getMessage());\r
201         }\r
202 \r
203     }\r
204 }\r
205 \r