BugFix:X-FromAppId configurable in AAiDataRouter
[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 public class AuditService {\r
54 \r
55     private static Logger logger = LoggerFactory.getInstance().getLogger(AuditService.class.getName());\r
56     private static Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(AuditService.class.getName());\r
57 \r
58     private static final String MEDIA_TYPE = MediaType.APPLICATION_JSON;\r
59     private static final String UNKNOWN_APP = "[unknown_app_id]";\r
60     private static final String RESULT_OK = "200 OK";\r
61 \r
62     private EventPublisher publisher;\r
63 \r
64     public AuditService(EventPublisher publisher) throws Exception {\r
65         this.publisher = publisher;\r
66     }\r
67 \r
68 \r
69     /**\r
70      * Handles an incoming post-orchestration audit request.\r
71      * Generates and posts audit events to DMaaP.\r
72      *\r
73      * @param content - JSON structure containing the request payload\r
74      * @param uri     - Http request uri\r
75      * @param headers - Http request headers\r
76      * @param uriInfo - Http URI info field\r
77      * @param req     - Http request structure.\r
78      * @return - Standard HTTP response.\r
79      *\r
80      */\r
81     @POST\r
82     @Path("/orchestration-event/")\r
83     @Consumes({MediaType.APPLICATION_JSON})\r
84     @Produces({MediaType.APPLICATION_JSON})\r
85     public Response triggerPOA(String content,\r
86             @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,\r
87             @Context HttpServletRequest req) {\r
88 \r
89         logger.debug("Incoming request..." + content);\r
90         Response response = null;\r
91         try {\r
92             Map<String, String> headerAttributes = initializeLogging(req, headers);\r
93 \r
94             List<String> serviceInstanceEvents = generateServiceInstanceEvents(headerAttributes, content);\r
95             processEvent(serviceInstanceEvents);\r
96 \r
97             response = Response.status(Status.OK).entity(RESULT_OK).type(MEDIA_TYPE).build();\r
98             LoggingUtil.logRestRequest(logger, auditLogger, req, response);\r
99 \r
100         } catch(POAAuditException e) {\r
101             response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();\r
102             LoggingUtil.logRestRequest(logger, auditLogger, req, response, e);\r
103         } finally {\r
104             LoggingUtil.closeMdc();\r
105         }\r
106         return response;\r
107     }\r
108 \r
109 \r
110     /**\r
111      * Initialize MDC logging using attributes from the request\r
112      * @param httpReq\r
113      * @param httpHeaders\r
114      * @return Returns a map of required header attributes\r
115      * @throws POAAuditException\r
116      */\r
117     private Map<String, String> initializeLogging(HttpServletRequest httpReq, HttpHeaders httpHeaders) throws POAAuditException {\r
118 \r
119         Map<String, String> headers = new HashMap<String, String>();\r
120         String remoteAddr = httpReq.getRemoteAddr();\r
121 \r
122         if (httpHeaders.getRequestHeaders() == null) {\r
123             String error="Missing Header";\r
124             throw new POAAuditException(error, Status.BAD_REQUEST, DataRouterMsgs.BAD_REST_REQUEST, error);\r
125         }\r
126         String transactionId = httpHeaders.getRequestHeaders().getFirst(Headers.TRANSACTION_ID);\r
127         if((transactionId == null) || transactionId.trim().isEmpty()) {\r
128             transactionId = UUID.randomUUID().toString();\r
129             logger.debug("Header " + Headers.TRANSACTION_ID + "not present in request, generating new value: " + transactionId);\r
130         }\r
131         headers.put(Headers.TRANSACTION_ID, transactionId);\r
132 \r
133         String fromAppId = httpHeaders.getRequestHeaders().getFirst(Headers.FROM_APP_ID);\r
134         if((fromAppId == null) || fromAppId.trim().isEmpty()) {\r
135             // initialize the context before throwing the exception\r
136             MdcContext.initialize(transactionId, DataRouterConstants.DATA_ROUTER_SERVICE_NAME, "", UNKNOWN_APP, remoteAddr);\r
137             String error = "Missing header attribute: " + Headers.FROM_APP_ID;\r
138             throw new POAAuditException(error, Status.BAD_REQUEST, DataRouterMsgs.BAD_REST_REQUEST, error);\r
139         }\r
140         headers.put(Headers.FROM_APP_ID, fromAppId);\r
141 \r
142         LoggingUtil.initMdc(transactionId, fromAppId, remoteAddr);\r
143 \r
144         return headers;\r
145     }\r
146 \r
147 \r
148 \r
149     /**\r
150      * Extracts service instances and generates a list of events\r
151      * @param eventHeaders\r
152      * @param requestBody\r
153      * @return Returns a list of service instances\r
154      * @throws POAAuditException if the request contains errors\r
155      */\r
156     private List<String> generateServiceInstanceEvents(Map<String, String> eventHeaders, String requestBody) throws POAAuditException {\r
157 \r
158         POAAuditEvent auditEvent = POAAuditEvent.fromJson(requestBody);\r
159         auditEvent.validate();\r
160 \r
161         List<String> eventMessages = new ArrayList<String>();\r
162         for (POAServiceInstanceEntity serviceInstance: auditEvent.getServiceInstanceList()) {\r
163             serviceInstance.validate();\r
164             serviceInstance.setxFromAppId(eventHeaders.get(Headers.FROM_APP_ID));\r
165             serviceInstance.setxTransactionId(eventHeaders.get(Headers.TRANSACTION_ID));\r
166             eventMessages.add(serviceInstance.toJson());\r
167         }\r
168         return eventMessages;\r
169     }\r
170 \r
171     /**\r
172      * Publish events to DMaaP.\r
173      * @param eventMessages\r
174      * @throws POAAuditException\r
175      *\r
176      * Note: The Default Transport Type in the DMaaPEventPublisher is defined as "HTTPAAF". Based on the deployment of DMaap, currently\r
177      * by default the "HTTPAUTH" transport type is supported.\r
178      */\r
179     private void processEvent(List<String> eventMessages) throws POAAuditException {\r
180 \r
181         int messagesSent = 0;\r
182         try {\r
183             messagesSent = publisher.sendSync(eventMessages);\r
184             logger.debug("The number of messages successfully sent: "+ messagesSent);\r
185 \r
186             if (messagesSent > 0) {\r
187                 logger.debug("Published Message: " + eventMessages);\r
188             } else {\r
189                 String exceptionStr = String.format("Failed to publish %d event(s) to DMaaP", eventMessages.size());\r
190                 logger.debug(exceptionStr);\r
191             }\r
192 \r
193 \r
194         } catch (Exception e) {\r
195             throw new POAAuditException("Failed to publish event to DMaaP: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR,\r
196                     DataRouterMsgs.EXCEPTION_DURING_METHOD_CALL, e.getMessage());\r
197         }\r
198 \r
199     }\r
200 }\r
201 \r