2 * ============LICENSE_START=======================================================
\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
12 * http://www.apache.org/licenses/LICENSE-2.0
\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
21 package org.onap.aai.datarouter.service;
\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
55 public class AuditService {
\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
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
65 private EventPublisher publisher;
\r
67 public AuditService(EventPublisher publisher) throws Exception {
\r
68 this.publisher = publisher;
\r
73 * Handles an incoming post-orchestration audit request.
\r
74 * Generates and posts audit events to DMaaP.
\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
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
92 logger.debug("Incoming request..." + content);
\r
93 Response response = null;
\r
95 Map<String, String> headerAttributes = initializeLogging(req, headers);
\r
97 List<String> serviceInstanceEvents = generateServiceInstanceEvents(headerAttributes, content);
\r
98 processEvent(serviceInstanceEvents);
\r
100 response = Response.status(Status.OK).entity(RESULT_OK).type(MEDIA_TYPE).build();
\r
101 LoggingUtil.logRestRequest(logger, auditLogger, req, response);
\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
107 LoggingUtil.closeMdc();
\r
114 * Initialize MDC logging using attributes from the request
\r
116 * @param httpHeaders
\r
117 * @return Returns a map of required header attributes
\r
118 * @throws POAAuditException
\r
120 private Map<String, String> initializeLogging(HttpServletRequest httpReq, HttpHeaders httpHeaders) throws POAAuditException {
\r
122 Map<String, String> headers = new HashMap<String, String>();
\r
123 String remoteAddr = httpReq.getRemoteAddr();
\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
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
134 headers.put(Headers.TRANSACTION_ID, transactionId);
\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
143 headers.put(Headers.FROM_APP_ID, fromAppId);
\r
145 LoggingUtil.initMdc(transactionId, fromAppId, remoteAddr);
\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
159 private List<String> generateServiceInstanceEvents(Map<String, String> eventHeaders, String requestBody) throws POAAuditException {
\r
161 POAAuditEvent auditEvent = POAAuditEvent.fromJson(requestBody);
\r
162 auditEvent.validate();
\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
171 return eventMessages;
\r
176 * Publish events to DMaaP.
\r
177 * @param eventMessages
\r
178 * @throws POAAuditException
\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
183 private void processEvent(List<String> eventMessages) throws POAAuditException {
\r
185 int messagesSent = 0;
\r
187 messagesSent = publisher.sendSync(eventMessages);
\r
188 logger.debug("The number of messages successfully sent: "+ messagesSent);
\r
190 if (messagesSent > 0) {
\r
191 logger.debug("Published Message: " + eventMessages);
\r
193 String exceptionStr = String.format("Failed to publish %d event(s) to DMaaP", eventMessages.size());
\r
194 logger.debug(exceptionStr);
\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