0521fb4df36a5765ab266bb85e60ee566e95718e
[so.git] / bpmn / MSOCommonBPMN / src / main / java / org / openecomp / mso / bpmn / common / workflow / service / WorkflowResource.java
1 /*-\r
2  * ============LICENSE_START=======================================================\r
3  * ONAP - SO\r
4  * ================================================================================\r
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.\r
6  * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.\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 \r
22 package org.openecomp.mso.bpmn.common.workflow.service;\r
23 \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 java.util.concurrent.atomic.AtomicLong;\r
29 \r
30 import javax.ws.rs.Consumes;\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.Response;\r
37 import javax.ws.rs.core.UriInfo;\r
38 \r
39 import org.camunda.bpm.engine.HistoryService;\r
40 import org.camunda.bpm.engine.ProcessEngineException;\r
41 import org.camunda.bpm.engine.ProcessEngineServices;\r
42 import org.camunda.bpm.engine.ProcessEngines;\r
43 import org.camunda.bpm.engine.RuntimeService;\r
44 import org.camunda.bpm.engine.history.HistoricVariableInstance;\r
45 import org.camunda.bpm.engine.runtime.ProcessInstance;\r
46 import org.camunda.bpm.engine.variable.VariableMap;\r
47 import org.camunda.bpm.engine.variable.Variables;\r
48 import org.camunda.bpm.engine.variable.Variables.SerializationDataFormats;\r
49 import org.camunda.bpm.engine.variable.impl.VariableMapImpl;\r
50 import org.openecomp.mso.bpmn.core.WorkflowException;\r
51 import org.openecomp.mso.logger.MessageEnum;\r
52 import org.openecomp.mso.logger.MsoLogger;\r
53 import org.slf4j.MDC;\r
54 \r
55 @Path("/workflow")\r
56 public class WorkflowResource {\r
57         \r
58         private ProcessEngineServices pes4junit = null;\r
59 \r
60         private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);\r
61         private static final String LOGMARKER = "[WRKFLOW-RESOURCE]";\r
62 \r
63         private static final int DEFAULT_WAIT_TIME = 30000;\r
64 \r
65         @Context\r
66         private UriInfo uriInfo = null;\r
67 \r
68         /**\r
69          * Starts the process instance and responds to client synchronously\r
70          * If the request does not contain mso-service-request-timeout then it waits for the value specified in DEFAULT_WAIT_TIME\r
71          * Note: value specified in mso-service-request-timeout is in seconds\r
72          * During polling time, if there is an exception encountered in the process execution then polling is stopped and the error response is \r
73          * returned to the client\r
74          * @param processKey\r
75          * @param variableMap\r
76          * @return\r
77          */\r
78         @POST\r
79         @Path("/services/{processKey}")\r
80         @Produces("application/json")\r
81         @Consumes("application/json")\r
82         public Response startProcessInstanceByKey(@PathParam("processKey") String processKey,\r
83                         VariableMapImpl variableMap) {\r
84 \r
85                 Map<String, Object> inputVariables = getInputVariables(variableMap);    \r
86                 setLogContext(processKey, inputVariables);\r
87 \r
88                 WorkflowResponse workflowResponse = new WorkflowResponse();\r
89                 long startTime = System.currentTimeMillis();\r
90                 ProcessInstance processInstance = null;\r
91 \r
92                 try {\r
93                         //Kickoff the process\r
94                         ProcessThread thread = new ProcessThread(inputVariables,processKey,msoLogger);\r
95                         thread.start();\r
96 \r
97                         Map<String, Object> responseMap = null;\r
98 \r
99                         //wait for process to be completed\r
100                         long waitTime = getWaitTime(inputVariables);\r
101                         long now = System.currentTimeMillis();\r
102                         long start = now;\r
103                         long endTime = start + waitTime;\r
104                         long pollingInterval = 500;\r
105 \r
106                         // TEMPORARY LOGIC FOR UNIT TEST REFACTORING\r
107                         // If this is a unit test (method is invoked directly), wait a max\r
108                         // of 5 seconds after process ended for a result.  In production,\r
109                         // wait up to 60 seconds.\r
110                         long timeToWaitAfterProcessEnded = uriInfo == null ? 5000 : 60000;\r
111                         AtomicLong timeProcessEnded = new AtomicLong(0);\r
112                         boolean endedWithNoResponse = false;\r
113 \r
114                         while (now <= endTime) {\r
115                                 Thread.sleep(pollingInterval);\r
116 \r
117                                 now = System.currentTimeMillis();\r
118 \r
119                                 // Increase the polling interval over time\r
120 \r
121                                 long elapsed = now - start;\r
122 \r
123                                 if (elapsed > 60000) {\r
124                                         pollingInterval = 5000;\r
125                                 } else if (elapsed > 10000) {\r
126                                         pollingInterval = 1000;\r
127                                 }\r
128                                 Exception exception = thread.getException();\r
129                                 if (exception != null) {\r
130                                         throw new Exception(exception);\r
131                                 }\r
132 \r
133                                 processInstance = thread.getProcessInstance();\r
134 \r
135                                 if (processInstance == null) {\r
136                                         msoLogger.debug(LOGMARKER + processKey + " process has not been created yet");\r
137                                         continue;\r
138                                 }\r
139 \r
140                                 String processInstanceId = processInstance.getId();\r
141                                 workflowResponse.setProcessInstanceID(processInstanceId);                               \r
142 \r
143                                 responseMap = getResponseMap(processInstance, processKey, timeProcessEnded);\r
144 \r
145                                 if (responseMap == null) {\r
146                                         msoLogger.debug(LOGMARKER + processKey + " has not produced a response yet");\r
147 \r
148                                         if (timeProcessEnded.longValue() != 0) {\r
149                                                 long elapsedSinceEnded = System.currentTimeMillis() - timeProcessEnded.longValue();\r
150 \r
151                                                 if (elapsedSinceEnded > timeToWaitAfterProcessEnded) {\r
152                                                         endedWithNoResponse = true;\r
153                                                         break;\r
154                                                 }\r
155                                         }\r
156                                 } else {\r
157                                         processResponseMap(workflowResponse, responseMap);\r
158                                         recordEvents(processKey, workflowResponse, startTime);\r
159                                         return Response.status(workflowResponse.getMessageCode()).entity(workflowResponse).build();\r
160                                 }\r
161                         }\r
162 \r
163                         //if we dont get response after waiting then send timeout response\r
164 \r
165                         String state;\r
166                         String processInstanceId;\r
167 \r
168                         if (processInstance == null) {\r
169                                 processInstanceId = "N/A";\r
170                                 state = "NOT STARTED";\r
171                         } else {\r
172                                 processInstanceId = processInstance.getProcessInstanceId();\r
173                                 state = isProcessEnded(processInstanceId) ? "ENDED" : "NOT ENDED";\r
174                         }\r
175 \r
176                         workflowResponse.setMessage("Fail");\r
177                         if (endedWithNoResponse) {\r
178                                 workflowResponse.setResponse("Process ended without producing a response");\r
179                         } else {\r
180                                 workflowResponse.setResponse("Request timed out, process state: " + state);\r
181                         }\r
182                         workflowResponse.setProcessInstanceID(processInstanceId);\r
183                         recordEvents(processKey, workflowResponse, startTime);\r
184                         workflowResponse.setMessageCode(500);\r
185                         return Response.status(500).entity(workflowResponse).build();\r
186                 } catch (Exception ex) {\r
187                         msoLogger.debug(LOGMARKER + "Exception in startProcessInstance by key",ex);\r
188                         workflowResponse.setMessage("Fail" );\r
189                         workflowResponse.setResponse("Error occurred while executing the process: " + ex.getMessage());\r
190                         if (processInstance != null) workflowResponse.setProcessInstanceID(processInstance.getId());\r
191                         \r
192                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG,  "BPMN", MDC.get(processKey), \r
193                                         MsoLogger.ErrorCode.UnknownError, LOGMARKER + workflowResponse.getMessage()\r
194                                         + " for processKey: " + processKey + " with response: " + workflowResponse.getResponse());\r
195                         \r
196                         workflowResponse.setMessageCode(500);\r
197                         recordEvents(processKey, workflowResponse, startTime);\r
198                         return Response.status(500).entity(workflowResponse).build();\r
199                 }\r
200         }\r
201 \r
202         /**\r
203          * Returns the wait time, this is used by the resource on how long it should wait to send a response\r
204          * If none specified DEFAULT_WAIT_TIME is used\r
205          * @param inputVariables\r
206          * @return\r
207          */\r
208         private int getWaitTime(Map<String, Object> inputVariables)\r
209         {\r
210                 String timeout = inputVariables.get("mso-service-request-timeout") == null\r
211                         ? null : inputVariables.get("mso-service-request-timeout").toString();          \r
212 \r
213                 if (timeout != null) {\r
214                         try {\r
215                                 return Integer.parseInt(timeout)*1000;\r
216                         } catch (NumberFormatException nex) {\r
217                                 msoLogger.debug("Invalid input for mso-service-request-timeout");\r
218                         }\r
219                 }\r
220                 return DEFAULT_WAIT_TIME;\r
221         }\r
222         \r
223         private void recordEvents(String processKey, WorkflowResponse response, long startTime) {\r
224                 \r
225                 msoLogger.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, \r
226                                 LOGMARKER + response.getMessage() + " for processKey: "\r
227                                 + processKey + " with response: " + response.getResponse(), "BPMN", MDC.get(processKey), null);\r
228                 \r
229                 msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, \r
230                                 LOGMARKER + response.getMessage() + " for processKey: "\r
231                                 + processKey + " with response: " + response.getResponse());\r
232         }\r
233 \r
234         private void setLogContext(String processKey, Map<String, Object> inputVariables) {\r
235                 MsoLogger.setServiceName("MSO." + processKey);\r
236                 if (inputVariables != null) {\r
237                         MsoLogger.setLogContext(getValueFromInputVariables(inputVariables, "mso-request-id"),\r
238                                 getValueFromInputVariables(inputVariables, "mso-service-instance-id"));\r
239                 }\r
240         }\r
241 \r
242         private String getValueFromInputVariables(Map<String,Object> inputVariables, String key) {\r
243                 Object value = inputVariables.get(key);\r
244                 if (value == null) {\r
245                         return "N/A";\r
246                 } else {\r
247                         return value.toString();\r
248                 }\r
249         }\r
250         \r
251         /**\r
252          * Checks to see if the specified process is ended.\r
253          * @param processInstanceId the process instance ID\r
254          * @return true if the process is ended\r
255          */\r
256         private boolean isProcessEnded(String processInstanceId) {\r
257                 ProcessEngineServices pes = getProcessEngineServices();\r
258                 try {\r
259                         return pes.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult() == null ? true : false ;\r
260                 } catch (Exception e) {\r
261                         msoLogger.debug("Exception :",e);\r
262                         return true;\r
263                 }        \r
264         }\r
265 \r
266         private void processResponseMap(WorkflowResponse workflowResponse, Map<String, Object> responseMap) {\r
267                 Object object = responseMap.get("Response");\r
268                 String response = object == null ? null : String.valueOf(object);\r
269                 if(response == null){\r
270                         object = responseMap.get("WorkflowResponse");\r
271                         response = object == null ? null : String.valueOf(object);\r
272                 }\r
273 \r
274                 workflowResponse.setResponse(response); \r
275 \r
276                 object = responseMap.get("ResponseCode");\r
277                 String responseCode = object == null ? null : String.valueOf(object);\r
278 \r
279                 try {\r
280                         workflowResponse.setMessageCode(Integer.parseInt(responseCode));\r
281                 } catch(NumberFormatException nex) {\r
282                         msoLogger.debug(LOGMARKER + "Failed to parse ResponseCode: " + responseCode);\r
283                         workflowResponse.setMessageCode(-1);\r
284                 }\r
285 \r
286                 Object status = responseMap.get("Status");\r
287 \r
288                 if ("Success".equalsIgnoreCase(String.valueOf(status))) {\r
289                         workflowResponse.setMessage("Success");\r
290                 } else if ("Fail".equalsIgnoreCase(String.valueOf(status))) {\r
291                         workflowResponse.setMessage("Fail");\r
292                 } else {\r
293                         msoLogger.debug(LOGMARKER + "Unrecognized Status: " + responseCode);\r
294                         workflowResponse.setMessage("Fail");\r
295                 }\r
296         }\r
297 \r
298         /**\r
299          * @version 1.0\r
300          * Triggers the workflow in a separate thread\r
301          */\r
302         private class ProcessThread extends Thread {\r
303                 private final Map<String,Object> inputVariables;\r
304                 private final String processKey;\r
305                 private final MsoLogger msoLogger;\r
306                 private final String businessKey;\r
307                 private ProcessInstance processInstance = null;\r
308                 private Exception exception = null;\r
309 \r
310                 public ProcessThread(Map<String, Object> inputVariables, String processKey, MsoLogger msoLogger) {\r
311                         this.inputVariables = inputVariables;\r
312                         this.processKey = processKey;\r
313                         this.msoLogger = msoLogger;\r
314                         this.businessKey = UUID.randomUUID().toString();\r
315                 }\r
316 \r
317                 /**\r
318                  * If an exception occurs when starting the process instance, it may\r
319                  * be obtained by calling this method.  Note that exceptions are only\r
320                  * recorded while the process is executing in its original thread.\r
321                  * Once a process is suspended, exception recording stops.\r
322                  * @return the exception, or null if none has occurred\r
323                  */\r
324                 public Exception getException() {\r
325                         return exception;\r
326                 }\r
327 \r
328                 \r
329                 public ProcessInstance getProcessInstance() {\r
330                         return this.processInstance;\r
331                 }\r
332                 \r
333                 /**\r
334                  * Sets the process instance exception.\r
335                  * @param exception the exception\r
336                  */\r
337                 private void setException(Exception exception) {\r
338                         this.exception = exception;\r
339                 }\r
340 \r
341                 public void run() {\r
342                         setLogContext(processKey, inputVariables);\r
343 \r
344                         long startTime = System.currentTimeMillis();\r
345                         \r
346                         try {\r
347                                 msoLogger.debug(LOGMARKER + "***Received MSO startProcessInstanceByKey with processKey:"\r
348                                         + processKey + " and variables: " + inputVariables);\r
349                                 \r
350                                 msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, LOGMARKER\r
351                                                 + "Call to MSO workflow/services in Camunda. Received MSO startProcessInstanceByKey with"\r
352                                                 + " processKey:" + processKey\r
353                                                 + " businessKey:" + businessKey\r
354                                                 + " variables: " + inputVariables);\r
355                                                 \r
356                                 RuntimeService runtimeService = getProcessEngineServices().getRuntimeService();\r
357 \r
358                                 // Note that this method doesn't return until the process suspends\r
359                                 // itself or finishes.  We provide a business key so we can identify\r
360                                 // the process instance immediately.\r
361                                 processInstance = runtimeService.startProcessInstanceByKey(\r
362                                         processKey, inputVariables);\r
363 \r
364                         } catch (Exception e) {\r
365                                 msoLogger.debug(LOGMARKER + "ProcessThread caught an exception executing "\r
366                                         + processKey + ": " + e);\r
367                                 setException(e);\r
368                         }\r
369                 }\r
370 \r
371         }\r
372 \r
373         private Map<String, Object> getInputVariables(VariableMapImpl variableMap) {\r
374                 VariableMap inputVariables = Variables.createVariables();\r
375                 @SuppressWarnings("unchecked")\r
376                 Map<String, Object> vMap = (Map<String, Object>) variableMap.get("variables");\r
377                 for (String key : vMap.keySet()) { //variabe name vn\r
378                         @SuppressWarnings("unchecked")\r
379                         Map<String, Object> valueMap = (Map<String,Object>)vMap.get(key); //value, type\r
380                         inputVariables.putValueTyped(key, Variables\r
381                         .objectValue(valueMap.get("value"))\r
382                         .serializationDataFormat(SerializationDataFormats.JAVA) // tells the engine to use java serialization for persisting the value\r
383                         .create());\r
384                 }\r
385                 return inputVariables;\r
386         }\r
387 \r
388         /**\r
389          * Attempts to get a response map from the specified process instance.\r
390          * @return the response map, or null if it is unavailable\r
391          */\r
392         private Map<String, Object> getResponseMap(ProcessInstance processInstance,\r
393                         String processKey, AtomicLong timeProcessEnded) {\r
394 \r
395                 String responseMapVariable = processKey + "ResponseMap";\r
396                 String processInstanceId = processInstance.getId();\r
397 \r
398                 // Query the runtime service to see if a response map is ready.\r
399 \r
400 /*              RuntimeService runtimeService = getProcessEngineServices().getRuntimeService();\r
401                 List<Execution> executions = runtimeService.createExecutionQuery()\r
402                         .processInstanceId(processInstanceId).list();\r
403 \r
404                 for (Execution execution : executions) {\r
405                         @SuppressWarnings("unchecked")\r
406                         Map<String, Object> responseMap = (Map<String, Object>)\r
407                                 getVariableFromExecution(runtimeService, execution.getId(),\r
408                                         responseMapVariable);\r
409 \r
410                         if (responseMap != null) {\r
411                                 msoLogger.debug(LOGMARKER + "Obtained " + responseMapVariable\r
412                                         + " from process " + processInstanceId + " execution "\r
413                                         + execution.getId());\r
414                                 return responseMap;\r
415                         }\r
416                 }\r
417 */\r
418                 //Querying history seem to return consistent results compared to querying the runtime service\r
419 \r
420                 boolean alreadyEnded = timeProcessEnded.longValue() != 0;\r
421 \r
422                 if (alreadyEnded || isProcessEnded(processInstance.getId())) {\r
423                         if (!alreadyEnded) {\r
424                                 timeProcessEnded.set(System.currentTimeMillis());\r
425                         }\r
426 \r
427                         // Query the history service to see if a response map exists.\r
428 \r
429                         HistoryService historyService = getProcessEngineServices().getHistoryService();\r
430                         @SuppressWarnings("unchecked")\r
431                         Map<String, Object> responseMap = (Map<String, Object>)\r
432                                 getVariableFromHistory(historyService, processInstance.getId(),\r
433                                         responseMapVariable);\r
434 \r
435                         if (responseMap != null) {\r
436                                 msoLogger.debug(LOGMARKER + "Obtained " + responseMapVariable\r
437                                         + " from process " + processInstanceId + " history");\r
438                                 return responseMap;\r
439                         }\r
440 \r
441                         // Query the history service for old-style response variables.\r
442 \r
443                         String prefix = (String) getVariableFromHistory(historyService, processInstanceId, "prefix");\r
444 \r
445                         if (prefix != null) {\r
446                                 \r
447                                 // Check for 'WorkflowResponse' variable\r
448                                 Object workflowResponseObject = getVariableFromHistory(historyService, processInstanceId, "WorkflowResponse");\r
449                                 String workflowResponse = workflowResponseObject == null ? null : String.valueOf(workflowResponseObject);\r
450                                 msoLogger.debug(LOGMARKER + "WorkflowResponse: " + workflowResponse);\r
451                                 \r
452                                 if (workflowResponse != null) {\r
453                                         Object responseCodeObject = getVariableFromHistory(historyService, processInstanceId, prefix + "ResponseCode");\r
454                                         String responseCode = responseCodeObject == null ? null : String.valueOf(responseCodeObject);\r
455                                         msoLogger.debug(LOGMARKER + prefix + "ResponseCode: " + responseCode);\r
456                                         responseMap = new HashMap<String, Object>();\r
457                                         responseMap.put("WorkflowResponse", workflowResponse);\r
458                                         responseMap.put("ResponseCode", responseCode);\r
459                                         responseMap.put("Status", "Success");\r
460                                         return responseMap;\r
461                                 }\r
462                                 \r
463                                 \r
464                                 // Check for 'WorkflowException' variable\r
465                                 WorkflowException workflowException = null;\r
466                                 String workflowExceptionText = null;\r
467 \r
468                                 Object workflowExceptionObject = getVariableFromHistory(historyService, processInstanceId, "WorkflowException");\r
469                                 if(workflowExceptionObject != null) {\r
470                                         if(workflowExceptionObject instanceof WorkflowException) {\r
471                                                 workflowException = (WorkflowException) workflowExceptionObject;\r
472                                                 workflowExceptionText = workflowException.toString();\r
473                                                 responseMap = new HashMap<String, Object>();\r
474                                                 responseMap.put("WorkflowException", workflowExceptionText);\r
475                                                 responseMap.put("ResponseCode", workflowException.getErrorCode());\r
476                                                 responseMap.put("Status", "Fail");\r
477                                                 return responseMap;\r
478                                         }\r
479                                         else if (workflowExceptionObject instanceof String) {\r
480                                                 Object object = getVariableFromHistory(historyService, processInstanceId, prefix + "ResponseCode");\r
481                                                 String responseCode = object == null ? null : String.valueOf(object);\r
482                                                 workflowExceptionText = (String) workflowExceptionObject;\r
483                                                 responseMap = new HashMap<String, Object>();\r
484                                                 responseMap.put("WorkflowException", workflowExceptionText);\r
485                                                 responseMap.put("ResponseCode", responseCode);\r
486                                                 responseMap.put("Status", "Fail");\r
487                                                 return responseMap;\r
488                                         }\r
489                                         \r
490                                 }\r
491                                 msoLogger.debug(LOGMARKER + "WorkflowException: " + workflowExceptionText);\r
492                                 \r
493                                 // BEGIN LEGACY SUPPORT.  TODO: REMOVE THIS CODE\r
494                                 Object object = getVariableFromHistory(historyService, processInstanceId, processKey + "Response");\r
495                                 String response = object == null ? null : String.valueOf(object);\r
496                                 msoLogger.debug(LOGMARKER + processKey + "Response: " + response);\r
497 \r
498                                 if (response != null) {\r
499                                         object = getVariableFromHistory(historyService, processInstanceId, prefix + "ResponseCode");\r
500                                         String responseCode = object == null ? null : String.valueOf(object);\r
501                                         msoLogger.debug(LOGMARKER + prefix + "ResponseCode: " + responseCode);\r
502                                         responseMap = new HashMap<String, Object>();\r
503                                         responseMap.put("Response", response);\r
504                                         responseMap.put("ResponseCode", responseCode);\r
505                                         responseMap.put("Status", "Success");\r
506                                         return responseMap;\r
507                                 }\r
508         \r
509                                 object = getVariableFromHistory(historyService, processInstanceId, prefix + "ErrorResponse");\r
510                                 String errorResponse = object == null ? null : String.valueOf(object);\r
511                                 msoLogger.debug(LOGMARKER + prefix + "ErrorResponse: " + errorResponse);\r
512 \r
513                                 if (errorResponse != null) {\r
514                                         object = getVariableFromHistory(historyService, processInstanceId, prefix + "ResponseCode");\r
515                                         String responseCode = object == null ? null : String.valueOf(object);\r
516                                         msoLogger.debug(LOGMARKER + prefix + "ResponseCode: " + responseCode);\r
517                                         responseMap = new HashMap<String, Object>();\r
518                                         responseMap.put("Response", errorResponse);\r
519                                         responseMap.put("ResponseCode", responseCode);\r
520                                         responseMap.put("Status", "Fail");\r
521                                         return responseMap;\r
522                                 }\r
523                                 // END LEGACY SUPPORT.  TODO: REMOVE THIS CODE\r
524                         }\r
525                 }\r
526                 return null;\r
527         }\r
528         \r
529         /**\r
530          * Gets a variable value from the specified execution.\r
531          * @return the variable value, or null if the variable could not be\r
532          * obtained\r
533          */\r
534         private Object getVariableFromExecution(RuntimeService runtimeService,\r
535                         String executionId, String variableName) {\r
536                 try {\r
537                         return runtimeService.getVariable(executionId, variableName);\r
538                 } catch (ProcessEngineException e) {\r
539                         // Most likely cause is that the execution no longer exists.\r
540                         msoLogger.debug("Error retrieving execution " + executionId\r
541                                 + " variable " + variableName + ": " + e);\r
542                         return null;\r
543                 }\r
544         }\r
545         /**\r
546          * Gets a variable value from specified historical process instance.\r
547          * @return the variable value, or null if the variable could not be\r
548          * obtained\r
549          */\r
550         private Object getVariableFromHistory(HistoryService historyService,\r
551                         String processInstanceId, String variableName) {\r
552                 try {\r
553                         HistoricVariableInstance v = historyService.createHistoricVariableInstanceQuery()\r
554                                 .processInstanceId(processInstanceId).variableName(variableName).singleResult();\r
555                         return v == null ? null : v.getValue();\r
556                 } catch (Exception e) {\r
557                         msoLogger.debug("Error retrieving process " + processInstanceId\r
558                                 + " variable " + variableName + " from history: " + e);\r
559                         return null;\r
560                 }\r
561         }\r
562         \r
563         @POST\r
564         @Path("/services/{processKey}/{processInstanceId}")\r
565         @Produces("application/json")\r
566         @Consumes("application/json")\r
567         public WorkflowResponse getProcessVariables(@PathParam("processKey") String processKey, @PathParam("processInstanceId") String processInstanceId) {\r
568                 //TODO filter only set of variables\r
569                 WorkflowResponse response = new WorkflowResponse();\r
570 \r
571                 long startTime = System.currentTimeMillis();\r
572                 try {\r
573                         ProcessEngineServices engine = getProcessEngineServices();\r
574                         List<HistoricVariableInstance> variables = engine.getHistoryService().createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list();\r
575                         Map<String,String> variablesMap = new HashMap<String,String>();\r
576                         for (HistoricVariableInstance variableInstance: variables) {\r
577                                 variablesMap.put(variableInstance.getName(), variableInstance.getValue().toString());\r
578                         }\r
579 \r
580                         msoLogger.debug(LOGMARKER + "***Received MSO getProcessVariables with processKey:" + processKey + " and variables: " + variablesMap.toString());\r
581                         \r
582                         msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, LOGMARKER \r
583                                         + "Call to MSO workflow/services in Camunda. Received MSO getProcessVariables with processKey:" \r
584                                         + processKey + " and variables: " \r
585                                         + variablesMap.toString());\r
586                         \r
587                         \r
588                         response.setVariables(variablesMap);\r
589                         response.setMessage("Success");\r
590                         response.setResponse("Successfully retrieved the variables"); \r
591                         response.setProcessInstanceID(processInstanceId);\r
592 \r
593                         msoLogger.debug(LOGMARKER + response.getMessage() + " for processKey: " + processKey + " with response: " + response.getResponse());\r
594                 } catch (Exception ex) {\r
595                         response.setMessage("Fail");\r
596                         response.setResponse("Failed to retrieve the variables," + ex.getMessage()); \r
597                         response.setProcessInstanceID(processInstanceId);\r
598                         \r
599                         msoLogger.error (MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "BPMN", MDC.get(processKey), MsoLogger.ErrorCode.UnknownError, LOGMARKER \r
600                                         + response.getMessage() \r
601                                         + " for processKey: " \r
602                                         + processKey \r
603                                         + " with response: " \r
604                                         + response.getResponse());\r
605                         msoLogger.debug("Exception :",ex);\r
606                 }\r
607                 \r
608                 msoLogger.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, \r
609                                 LOGMARKER + response.getMessage() + " for processKey: "\r
610                                 + processKey + " with response: " + response.getResponse(), "BPMN", MDC.get(processKey), null);\r
611                 \r
612                 msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, \r
613                                 LOGMARKER + response.getMessage() + " for processKey: "\r
614                                 + processKey + " with response: " + response.getResponse());\r
615                 \r
616                 return response;\r
617         }\r
618 \r
619         private ProcessEngineServices getProcessEngineServices() {\r
620                 if (pes4junit == null) {\r
621                         return ProcessEngines.getProcessEngine("infrastructure");\r
622                 } else {\r
623                         return pes4junit;\r
624                 }\r
625         }\r
626 \r
627         public void setProcessEngineServices4junit(ProcessEngineServices pes) {\r
628                 pes4junit = pes;\r
629         }\r
630 }\r