Initial OpenECOMP MSO commit
[so.git] / bpmn / MSOGammaBPMN / src / main / java / org / openecomp / mso / bpmn / gamma / workflow / service / VnfAdapterRestNotifyResource.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * OPENECOMP - MSO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.mso.bpmn.gamma.workflow.service;
22
23 import java.io.StringReader;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import javax.ws.rs.Consumes;
28 import javax.ws.rs.POST;
29 import javax.ws.rs.Path;
30 import javax.ws.rs.Produces;
31 import javax.ws.rs.core.MediaType;
32 import javax.ws.rs.core.Response;
33 import javax.xml.parsers.DocumentBuilder;
34 import javax.xml.parsers.DocumentBuilderFactory;
35
36 import org.camunda.bpm.BpmPlatform;
37 import org.camunda.bpm.engine.MismatchingMessageCorrelationException;
38 import org.camunda.bpm.engine.ProcessEngineServices;
39 import org.camunda.bpm.engine.RuntimeService;
40 import org.slf4j.MDC;
41 import org.w3c.dom.Document;
42 import org.w3c.dom.Element;
43 import org.w3c.dom.Node;
44 import org.w3c.dom.NodeList;
45 import org.xml.sax.InputSource;
46
47 import org.openecomp.mso.logger.MessageEnum;
48 import org.openecomp.mso.logger.MsoLogger;
49
50 /**
51  * Listens for REST notifications from the VNF Adapter and injects each one
52  * into a waiting BPMN processes.
53  */
54 @Path("/vnfAdapterRestNotify")
55 public class VnfAdapterRestNotifyResource {
56         private static final MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
57         private static final String LOGMARKER = "[VNF-REST-NOTIFY]";
58
59         private ProcessEngineServices pes4junit = null;
60         
61         @POST
62         @Path("/")
63         @Consumes(MediaType.APPLICATION_XML)
64         @Produces(MediaType.TEXT_PLAIN)
65         public Response notify(String content) {
66                 LOGGER.debug(LOGMARKER + " Received VNF Adapter REST Notification:"
67                         + System.lineSeparator() + content);
68
69                 String messageId = null;
70                 long startTime = System.currentTimeMillis();
71                 
72                 try {
73                         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
74                         factory.setNamespaceAware(true);
75                         DocumentBuilder builder = factory.newDocumentBuilder();
76                         InputSource source = new InputSource(new StringReader(content));
77                         Document doc = builder.parse(source);
78                         doc.normalize();
79
80                         Element rootElement = doc.getDocumentElement();
81                         NodeList childList = rootElement.getChildNodes();
82
83                         for (int i = 0; i < childList.getLength(); i++) {
84                                 Node childNode = childList.item(i);
85                                 if (childNode.getNodeType() == Node.ELEMENT_NODE) {
86                                         Element childElement = (Element) childNode;
87
88                                         String childElementName = childElement.getLocalName();
89                                         if (childElementName == null) {
90                                                 childElementName = childElement.getNodeName();
91                                         }
92
93                                         if ("messageId".equals(childElementName)) {
94                                                 messageId = childElement.getTextContent();
95                                         }
96                                 }
97                         }
98                 } catch (Exception e) {
99                         String msg = "Failed to parse VNF Adapter REST Notification: " + e;
100                         LOGGER.debug(LOGMARKER + " " + msg);
101                         LOGGER.error(MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.DataError, LOGMARKER + ":" + msg, e);
102                         
103                         return Response.status(400).entity(e).build();
104                 }
105
106                 if (messageId == null || messageId.isEmpty()) {
107                         String msg = "No messageId in VNF Adapter REST Notification";
108                         LOGGER.debug(LOGMARKER + " " + msg);
109                         LOGGER.error(MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.DataError, LOGMARKER + ":" + msg);
110                         
111                         return Response.status(400).entity(msg).build();
112                 }
113
114                 MsoLogger.setServiceName("MSO." + "vnfAdapterRestNotify");
115                 MsoLogger.setLogContext(messageId, "N/A");
116
117                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Call to MSO vnfAdapterRestNotify ");
118
119                 try {
120                         ProcessEngineServices pes = getProcessEngineServices();
121                         RuntimeService runtimeService = pes.getRuntimeService();
122
123                         if (!isReadyforCorrelation(runtimeService, "VNFREST_messageId", messageId, "vnfAdapterRestCallbackMessage")) {
124                                 String msg = "No process is waiting to receive vnfAdapterRestCallbackMessage with VNFREST_messageId='" + messageId + "'";
125                                 LOGGER.debug(LOGMARKER + " " + msg);
126                                 LOGGER.error(MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, LOGMARKER + ":" + msg);
127                                 
128                                 LOGGER.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, 
129                                                 LOGMARKER + "Call to MSO vnfAdapterRestNotify ", "BPMN", MsoLogger.getServiceName(), "vnfAdapterRestNotify");
130                                 
131                                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Call to MSO VnfAdapterNotifyService ");
132                                 
133                                 
134                                 return Response.status(500).entity(msg).build();
135                         }
136
137                         Map<String,Object> variables = new HashMap<String,Object>();
138                         variables.put("VNFREST_messageId", messageId);
139                         variables.put("VNFREST_callback", content);
140
141                         runtimeService.createMessageCorrelation("vnfAdapterRestCallbackMessage").setVariables(variables)
142                                   .processInstanceVariableEquals("VNFREST_messageId", messageId).correlate();
143
144                         LOGGER.debug(LOGMARKER + " Completed processing of VNF Adapter REST Notification");
145                 } catch (MismatchingMessageCorrelationException e) {
146                         LOGGER.debug(LOGMARKER + "[CORM] correlation id mismatch");
147                         String msg = "vnfAdapterRestNotify received a notification with messageId='"
148                                 + messageId + "' but it could not be correlated to any active process - ignoring the request";
149                         LOGGER.debug(msg);
150                         LOGGER.error(MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, LOGMARKER, e);
151                         
152                         LOGGER.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.InternalError, 
153                                         LOGMARKER + "Completed vnfAdapterRestNotify with error ", "BPMN", MsoLogger.getServiceName(), "vnfAdapterRestNotify");
154                         
155                         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.InternalError, "Completed vnfAdapterRestNotify with error ");
156                         
157                         return Response.status(500).entity(msg).build();
158                 }
159                 LOGGER.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, 
160                                 LOGMARKER + "Completed vnfAdapterRestNotify", "BPMN", MsoLogger.getServiceName(), "vnfAdapterRestNotify");
161                 
162                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Completed vnfAdapterRestNotify");
163                 
164                 return Response.status(204).build();
165         }
166         
167         private boolean isReadyforCorrelation(RuntimeService runtimeService,
168                         String correlationVariable, String correlationValue, String messageName) {
169                 long waitingInstances = runtimeService.createExecutionQuery()
170                         .messageEventSubscriptionName(messageName)
171                         .processVariableValueEquals(correlationVariable, correlationValue)
172                         .count();
173
174                 int retries = 50;
175                 while (waitingInstances == 0 && retries > 0) {
176                         try {
177                                 Thread.sleep(100);
178                         } catch (InterruptedException e) {
179                                 LOGGER.error(MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, LOGMARKER, e);
180                                 
181                                 return false;
182                         }
183
184                         waitingInstances = runtimeService.createExecutionQuery()
185                                 .messageEventSubscriptionName(messageName)
186                                 .processVariableValueEquals(correlationVariable, correlationValue)
187                                 .count();
188
189                         retries--;
190                 }
191                 
192                 return waitingInstances != 0;
193         }
194         
195         private ProcessEngineServices getProcessEngineServices() {
196                 if (pes4junit == null) {
197                         return BpmPlatform.getDefaultProcessEngine();
198                 } else {
199                         return pes4junit;
200                 }
201         }
202
203         public void setProcessEngineServices4junit(ProcessEngineServices pes) {
204                 pes4junit = pes;
205         }
206 }