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