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