[MSO-8] Second step of the rebase for MSO
[so.git] / bpmn / MSOCommonBPMN / src / main / java / org / openecomp / mso / bpmn / common / workflow / service / SDNCAdapterCallbackServiceImpl.java
1 /*-\r
2  * ============LICENSE_START=======================================================\r
3  * OPENECOMP - MSO\r
4  * ================================================================================\r
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.\r
6  * ================================================================================\r
7  * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * you may not use this file except in compliance with the License.\r
9  * You may obtain a copy of the License at\r
10  * \r
11  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * \r
13  * Unless required by applicable law or agreed to in writing, software\r
14  * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * See the License for the specific language governing permissions and\r
17  * limitations under the License.\r
18  * ============LICENSE_END=========================================================\r
19  */\r
20 \r
21 package org.openecomp.mso.bpmn.common.workflow.service;\r
22 \r
23 import java.util.HashMap;\r
24 import java.util.Map;\r
25 \r
26 import javax.jws.WebMethod;\r
27 import javax.jws.WebParam;\r
28 import javax.jws.WebResult;\r
29 import javax.jws.WebService;\r
30 import javax.ws.rs.core.Context;\r
31 import javax.xml.ws.WebServiceContext;\r
32 \r
33 import org.camunda.bpm.BpmPlatform;\r
34 import org.camunda.bpm.engine.MismatchingMessageCorrelationException;\r
35 import org.camunda.bpm.engine.ProcessEngineServices;\r
36 import org.camunda.bpm.engine.RuntimeService;\r
37 import org.camunda.bpm.engine.runtime.ExecutionQuery;\r
38 import org.openecomp.mso.bpmn.common.adapter.sdnc.SDNCAdapterCallbackRequest;\r
39 import org.openecomp.mso.bpmn.common.adapter.sdnc.SDNCAdapterResponse;\r
40 import org.openecomp.mso.bpmn.common.adapter.sdnc.SDNCCallbackAdapterPortType;\r
41 import org.openecomp.mso.bpmn.core.PropertyConfiguration;\r
42 import org.openecomp.mso.logger.MessageEnum;\r
43 import org.openecomp.mso.logger.MsoLogger;\r
44 /**\r
45  * @version 1.0\r
46  *  \r
47  */\r
48 @WebService(serviceName="SDNCAdapterCallbackService", targetNamespace="http://org.openecomp/workflow/sdnc/adapter/schema/v1")\r
49 public class SDNCAdapterCallbackServiceImpl implements SDNCCallbackAdapterPortType {\r
50 \r
51         private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);\r
52         private final int DEFAULT_RETRY_ATTEMPTS = 60;\r
53         private final int DEFAULT_SLEEP_TIME = 500;\r
54 \r
55         private final String logMarker = "[SDNC-CALLBACK]";\r
56 \r
57         @Context WebServiceContext wsContext;\r
58 \r
59         private volatile ProcessEngineServices pes4junit = null;\r
60 \r
61         @WebMethod(operationName = "SDNCAdapterCallback")\r
62     @WebResult(name = "SDNCAdapterResponse", targetNamespace = "http://org.openecomp/workflow/sdnc/adapter/schema/v1", partName = "SDNCAdapterCallbackResponse")\r
63     public SDNCAdapterResponse sdncAdapterCallback(\r
64             @WebParam(name = "SDNCAdapterCallbackRequest", targetNamespace = "http://org.openecomp/workflow/sdnc/adapter/schema/v1", partName = "SDNCAdapterCallbackRequest")\r
65             SDNCAdapterCallbackRequest sdncAdapterCallbackRequest) {\r
66 \r
67                 //Callback URL to use http://localhost:28080/mso/SDNCAdapterCallbackService\r
68                 ProcessEngineServices pes = getProcessEngineServices();\r
69                 RuntimeService runtimeService = pes.getRuntimeService();\r
70                 String receivedRequestId = sdncAdapterCallbackRequest.getCallbackHeader().getRequestId();\r
71                 MsoLogger.setServiceName("MSO." + "sdncAdapter");\r
72                 MsoLogger.setLogContext(receivedRequestId, "N/A");\r
73                 msoLogger.debug(logMarker + "Received callback response:" + sdncAdapterCallbackRequest.toString());\r
74                 SDNCAdapterResponse sdncAdapterResponse;\r
75                 long startTime = System.currentTimeMillis();\r
76 \r
77                 /*Correlating the response with the running instance*/\r
78 \r
79                 // NOTE: the following loop is a workaround for problems we've had\r
80                 // with reliability of the runtime service.  It seems that queries\r
81                 // sometimes return results, and sometimes they don't.  This might\r
82                 // be a problem in mysql only.  We aren't sure if it affects camunda\r
83                 // on oracle or mariadb.  The workaround is to repeat the request\r
84                 // a number of times until it succeeds.  If it doesn't succeed after\r
85                 // 60 tries, then we give up.\r
86 \r
87                 int maxAttempts = DEFAULT_RETRY_ATTEMPTS;\r
88                 int attempt = 1;\r
89                 int sleepTime = DEFAULT_SLEEP_TIME;\r
90 \r
91                 Map<String,String> bpmnProperties = getMSOBPMNURNProperties();\r
92                 if (bpmnProperties != null) {\r
93                         try {\r
94                                 maxAttempts = Integer.parseInt(bpmnProperties.get("mso.callbackRetryAttempts"));\r
95                                 msoLogger.debug(logMarker + "mso.callbackRetryAttempts=" + maxAttempts);\r
96                                 sleepTime = Integer.parseInt(bpmnProperties.get("mso.callbackRetrySleepTime"));\r
97                                 msoLogger.debug(logMarker + "mso.callbackRetrySleepTime:" + sleepTime);\r
98                         } catch (Exception ex) {\r
99                                 \r
100                         msoLogger.debug (logMarker                                              \r
101                                                 + "Error parsing mso.callbackRetrySleepTime/mso.callbackRetryAttempts:" \r
102                                                 + sleepTime + ":" \r
103                                                 + maxAttempts);\r
104                                 \r
105                         }\r
106                 }\r
107 \r
108                 /* Check to make sure the process instance is reay for correlation*/\r
109                 try{\r
110                         isReadyforCorrelation(runtimeService, receivedRequestId, maxAttempts, sleepTime );\r
111                 }catch(Exception e){\r
112                         String msg =\r
113                                 "SDNC Adapter Callback Service received a SDNC Adapter Callback Request with RequestId '"\r
114                                                 + receivedRequestId\r
115                                                 + "' but that RequestId doesn't exist or has timed out waiting for the callback";\r
116                         sdncAdapterResponse = new SDNCAdapterExceptionResponse(e);\r
117                         \r
118                         msoLogger.error (MessageEnum.BPMN_SDNC_CALLBACK_EXCEPTION, "BPMN", MsoLogger.getServiceName(), \r
119                                         MsoLogger.ErrorCode.UnknownError, logMarker + ":" + msg, e);\r
120                         \r
121                         msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, logMarker \r
122                                         + "Completed the execution of MSO SDNCAdapterCallbackService." );\r
123                         \r
124                         msoLogger.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, \r
125                                         logMarker + "Completed the execution of MSO SDNCAdapterCallbackService.", "BPMN", \r
126                                         MsoLogger.getServiceName(), "sdncAdapterCallback");\r
127                         \r
128                         return sdncAdapterResponse;\r
129                 }\r
130 \r
131                 msoLogger.debug(logMarker + "*** Received MSO sdncAdapterCallbackService ******");\r
132                 \r
133                 msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Call to MSO sdncAdapterCallbackService");            \r
134                 \r
135                 msoLogger.debug(logMarker + "Callback response string:\n"  + sdncAdapterCallbackRequest.toString());\r
136 \r
137                 String reqId = receivedRequestId;\r
138                 Map<String,Object> variables = new HashMap<String,Object>();\r
139                 variables.put("SDNCA_requestId", reqId );\r
140                 variables.put("sdncAdapterCallbackRequest", sdncAdapterCallbackRequest.toString());\r
141                 while (true) {\r
142                         try {\r
143                                 // sdncAdapterCallbackRequest is the message event name (defined in the bpmn process)\r
144                                 runtimeService.createMessageCorrelation("sdncAdapterCallbackRequest")\r
145                                         .setVariables(variables)\r
146                                         .processInstanceVariableEquals("SDNCA_requestId", reqId).correlate();\r
147                                 sdncAdapterResponse = new SDNCAdapterResponse();\r
148                                 msoLogger.debug(logMarker + "***** Completed processing of MSO sdncAdapterCallbackService ******");\r
149                                 \r
150                                 msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, logMarker \r
151                                                 + "Completed the execution of MSO SDNCAdapterCallbackService.");\r
152                                 \r
153                                 msoLogger.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, \r
154                                                 logMarker + "Completed the execution of MSO SDNCAdapterCallbackService.", "BPMN", \r
155                                                 MsoLogger.getServiceName(), "sdncAdapterCallback");\r
156                                 \r
157                                 return sdncAdapterResponse;\r
158                         } catch(MismatchingMessageCorrelationException e) {\r
159                                 msoLogger.debug(logMarker + "[CORM]correlation id mismatch (attempt " + attempt + "/" + maxAttempts + ")");\r
160                                 if (attempt == maxAttempts) {\r
161                                         // Couldn't correlate requestId to any active flow\r
162                                         //MsoLogger logger = MsoLogger.getMsoLogger("SDNCAdapterCallbackService");\r
163                                         String msg =\r
164                                                 "SDNC Adapter Callback Service received a SDNC Adapter Callback Request with RequestId '"\r
165                                                                 + receivedRequestId\r
166                                                                 + "' but that RequestId could not be correlated to any active process - ignoring the Request";\r
167                                         sdncAdapterResponse = new SDNCAdapterExceptionResponse(e);\r
168                                         \r
169                                         msoLogger.error (MessageEnum.BPMN_SDNC_CALLBACK_EXCEPTION, "BPMN", MsoLogger.getServiceName(), \r
170                                                         MsoLogger.ErrorCode.UnknownError, logMarker + ":" + msg, e);\r
171                                         \r
172                                         msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, logMarker \r
173                                                         + "Completed the execution of MSO SDNCAdapterCallbackService." );\r
174                                         \r
175                                         msoLogger.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, \r
176                                                         logMarker + "Completed the execution of MSO SDNCAdapterCallbackService.", "BPMN", \r
177                                                         MsoLogger.getServiceName(), "sdncAdapterCallback");\r
178                                         \r
179                                         return sdncAdapterResponse;\r
180                                 }\r
181 \r
182                                 try {\r
183                                         Thread.sleep(sleepTime);\r
184                                 } catch (InterruptedException e2) {\r
185                                         String msg =\r
186                                                 "SDNC Adapter Callback Service received a SDNC Adapter Callback Request with RequestId '"\r
187                                                                 + receivedRequestId\r
188                                                                 + "' but correlation was interrupted";\r
189                                         sdncAdapterResponse = new SDNCAdapterExceptionResponse(e);\r
190                                         \r
191                                         msoLogger.error (MessageEnum.BPMN_SDNC_CALLBACK_EXCEPTION, "BPMN", MsoLogger.getServiceName(), \r
192                                                         MsoLogger.ErrorCode.UnknownError, logMarker + ":" + msg, e);\r
193                                         \r
194                                         msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, logMarker \r
195                                                         + "Completed the execution of MSO SDNCAdapterCallbackService.");\r
196                                         \r
197                                         msoLogger.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, \r
198                                                         logMarker + "Completed the execution of MSO SDNCAdapterCallbackService.", "BPMN", \r
199                                                         MsoLogger.getServiceName(), "sdncAdapterCallback");\r
200                                         \r
201                                         return sdncAdapterResponse;\r
202                                 }\r
203                         }\r
204 \r
205                         attempt++;\r
206                 }\r
207         }\r
208 \r
209 \r
210         private Map<String,String> getMSOBPMNURNProperties() {\r
211                 PropertyConfiguration propertyConfiguration = PropertyConfiguration.getInstance();\r
212                 Map<String,String> props = propertyConfiguration.getProperties("mso.bpmn.urn.properties");\r
213                 return props;\r
214         }\r
215 \r
216         private void isReadyforCorrelation(RuntimeService runtimeService,\r
217                         String receivedRequestId, int retries, int sleepTime){\r
218                 ExecutionQuery waitingInstances = null;\r
219                 long waitingInstancesCount = 0;\r
220 \r
221                 //Workaround for performance testing, explicit wait for a second for the transactions to be committed\r
222                 //Also check to make sure the process didn't timeout before trying to correlate\r
223                 \r
224                 do{\r
225                   waitingInstances = runtimeService.createExecutionQuery() //\r
226                                         .messageEventSubscriptionName("sdncAdapterCallbackRequest")\r
227                                         .processVariableValueEquals("SDNCA_requestId", receivedRequestId);\r
228                   waitingInstancesCount = waitingInstances.count();\r
229                   retries--;\r
230                   msoLogger.debug(logMarker + "waitingInstancesCount: " + waitingInstancesCount);\r
231                   try {\r
232                                 Thread.sleep(sleepTime);\r
233                           } catch (InterruptedException e) {\r
234                                 \r
235                                 msoLogger.error (MessageEnum.BPMN_SDNC_CALLBACK_EXCEPTION, "BPMN", MsoLogger.getServiceName(), \r
236                                                 MsoLogger.ErrorCode.UnknownError, logMarker, e);\r
237                                 \r
238                           }\r
239                 }while (waitingInstancesCount==0 && retries > 0); \r
240                 if(waitingInstancesCount > 0){\r
241                         msoLogger.debug(logMarker + "waitingInstancesCount before timeout check: " + waitingInstancesCount);\r
242                         waitingInstancesCount = waitingInstances.processVariableValueEquals("asynchronousResponseTimeout", false).count();\r
243                         msoLogger.debug(logMarker + "waitingInstancesCount after timeout check: " + waitingInstancesCount);\r
244                         if(waitingInstancesCount<=0){\r
245                                 msoLogger.debug(logMarker + "detected timeout on flow to correlate");\r
246                                 throw new IllegalStateException("process timed out");\r
247                         }\r
248                 }else{\r
249                         //flow may have already ended, so can't check timeout variable. Throw exception?\r
250                         msoLogger.debug(logMarker + "no flow to correlate to");\r
251                         throw new IllegalStateException("no flow to correlate to");\r
252                 }\r
253         }\r
254 \r
255         private ProcessEngineServices getProcessEngineServices() {\r
256                 if (pes4junit == null) {\r
257                         return BpmPlatform.getDefaultProcessEngine();\r
258                 } else {\r
259                         return pes4junit;\r
260                 }\r
261         }\r
262 \r
263         @WebMethod(exclude=true)\r
264         public void setProcessEngineServices4junit(ProcessEngineServices pes) {\r
265                 pes4junit = pes;\r
266         }\r
267 \r
268         public class SDNCAdapterExceptionResponse extends SDNCAdapterResponse {\r
269                 private Exception ex;\r
270 \r
271                 public SDNCAdapterExceptionResponse(Exception ex) {\r
272                         super();\r
273                         this.ex = ex;\r
274                 }\r
275 \r
276                 public Exception getException() {\r
277                         return ex;\r
278                 }\r
279         }\r
280 }\r