[MSO-8] Update the maven dependency
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / openecomp / mso / bpmn / common / scripts / AbstractServiceTaskProcessor.groovy
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.scripts;
22
23 import groovy.json.JsonSlurper
24
25 import org.camunda.bpm.engine.delegate.BpmnError
26 import org.camunda.bpm.engine.runtime.Execution
27 import org.camunda.bpm.engine.variable.VariableMap
28 import org.camunda.bpm.engine.variable.Variables
29 import org.camunda.bpm.engine.variable.Variables.SerializationDataFormats
30 import org.camunda.bpm.engine.variable.impl.value.ObjectValueImpl
31 import org.openecomp.mso.bpmn.common.workflow.service.WorkflowCallbackResponse
32 import org.openecomp.mso.bpmn.common.workflow.service.WorkflowContextHolder
33 import org.openecomp.mso.bpmn.core.WorkflowException
34 import org.springframework.web.util.UriUtils
35
36 public abstract class AbstractServiceTaskProcessor implements ServiceTaskProcessor {
37         public MsoUtils utils = new MsoUtils()
38
39
40         /**
41          * Logs a message at the ERROR level.
42          * @param message the message
43          */
44         public void logError(String message) {
45                 log('ERROR', message, null, "true")
46         }
47
48         /**
49          * Logs a message at the ERROR level.
50          * @param message the message
51          * @param cause the cause (stracktrace will be included in the output)
52          */
53         public void logError(String message, Throwable cause) {
54                 log('ERROR', message, cause, "true")
55         }
56
57         /**
58          * Logs a message at the WARN level.
59          * @param message the message
60          */
61         public void logWarn(String message) {
62                 log('WARN', message, null, "true")
63         }
64
65         /**
66          * Logs a message at the WARN level.
67          * @param message the message
68          * @param cause the cause (stracktrace will be included in the output)
69          */
70         public void logWarn(String message, Throwable cause) {
71                 log('WARN', message, cause, "true")
72         }
73
74         /**
75          * Logs a message at the INFO level.
76          * @param message the message
77          */
78         public void logInfo(String message) {
79                 log('INFO', message, null, "true")
80         }
81
82         /**
83          * Logs a message at the INFO level.
84          * @param message the message
85          * @param cause the cause (stracktrace will be included in the output)
86          */
87         public void logInfo(String message, Throwable cause) {
88                 log('INFO', message, cause, "true")
89         }
90
91         /**
92          * Logs a message at the DEBUG level.
93          * @param message the message
94          * @param isDebugLogEnabled a flag indicating if DEBUG level is enabled
95          */
96         public void logDebug(String message, String isDebugLogEnabled) {
97                 log('DEBUG', message, null, isDebugLogEnabled)
98         }
99
100         /**
101          * Logs a message at the DEBUG level.
102          * @param message the message
103          * @param cause the cause (stracktrace will be included in the output)
104          * @param isDebugLogEnabled a flag indicating if DEBUG level is enabled
105          */
106         public void logDebug(String message, Throwable cause, String isDebugLogEnabled) {
107                 log('DEBUG', message, cause, isDebugLogEnabled)
108         }
109
110         /**
111          * Logs a message at the specified level.
112          * @param level the level (DEBUG, INFO, WARN, ERROR)
113          * @param message the message
114          * @param isLevelEnabled a flag indicating if the level is enabled
115          *        (used only at the DEBUG level)
116          */
117         public void log(String level, String message, String isLevelEnabled) {
118                 log(level, message,  null, isLevelEnabled)
119         }
120
121         /**
122          * Logs a message at the specified level.
123          * @param level the level (DEBUG, INFO, WARN, ERROR)
124          * @param message the message
125          * @param cause the cause (stracktrace will be included in the output)
126          * @param isLevelEnabled a flag indicating if the level is enabled
127          *        (used only at the DEBUG level)
128          */
129         public void log(String level, String message, Throwable cause, String isLevelEnabled) {
130                 if (cause == null) {
131                         utils.log(level, message, isLevelEnabled);
132                 } else {
133                         StringWriter stringWriter = new StringWriter();
134                         PrintWriter printWriter = new PrintWriter(stringWriter);
135                         printWriter.println(message);
136                         cause.printStackTrace(printWriter);
137                         utils.log(level, stringWriter.toString(), isLevelEnabled);
138                         printWriter.close();
139                 }
140         }
141
142         /**
143          * Logs a WorkflowException at the ERROR level with the specified message.
144          * @param execution the execution
145          */
146         public void logWorkflowException(Execution execution, String message) {
147                 def workflowException = execution.getVariable("WorkflowException")
148
149                 if (workflowException == null) {
150                         logError(message);
151                 } else {
152                         logError(message + ": " + workflowException)
153                 }
154         }
155
156         /**
157          * Saves the WorkflowException in the execution to the specified variable,
158          * clearing the WorkflowException variable so the workflow can continue
159          * processing (perhaps catching another WorkflowException).
160          * @param execution the execution
161          * @return the name of the destination variable
162          */
163         public saveWorkflowException(Execution execution, String variable) {
164                 if (variable == null) {
165                         throw new NullPointerException();
166                 }
167
168                 execution.setVariable(variable, execution.getVariable("WorkflowException"))
169                 execution.setVariable("WorkflowException", null)
170         }
171
172         /**
173          * Builds a success response from the specified message content and numeric
174          * response code.  The response code may be an integer or a string representation
175          * of an integer.  The response is stored in the execution where it may be
176          * picked up by the Workflow service.
177          * <p>
178          * IMPORTANT: the activity that executes this method should have an
179          * asynchronous continuation after it to ensure the execution variables
180          * are persisted to the database.
181          * @param execution the execution
182          * @param content the message content
183          * @param responseCode the message response code
184          */
185         @Deprecated
186         public void buildResponse(Execution execution, String content, Object responseCode) {
187                 buildResponse(execution, content, responseCode, true)
188         }
189
190         /**
191          * Builds a standard error response containing the specified error message and
192          * numeric response code.  The response code may be an integer or a string
193          * representation of an integer.  The response is stored in the execution where
194          * it may be picked up by the Workflow service.
195          * <p>
196          * IMPORTANT: the activity that executes this method should have an
197          * asynchronous continuation after it to ensure the execution variables
198          * are persisted to the database.
199          * @param execution the execution
200          * @param content the message content
201          * @param errorCode the message response code
202          */
203         @Deprecated
204         public void buildErrorResponse(Execution execution, String errorMessage, Object errorCode) {
205
206                 def encErrorMessage = errorMessage.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
207
208                 def content = """
209                         <aetgt:WorkflowException xmlns:aetgt="http://org.openecomp/mso/workflow/schema/v1">
210                         <aetgt:ErrorMessage>${encErrorMessage}</aetgt:ErrorMessage>
211                         <aetgt:ErrorCode>${errorCode}</aetgt:ErrorCode>
212                         </aetgt:WorkflowException>
213                   """
214
215                 buildResponse(execution, content, errorCode, false)
216         }
217
218         // BEGIN LEGACY SUPPORT.  TODO: REMOVE THIS CODE
219         /**
220          * Builds a standard error response containing the specified error message
221          * and a numeric response code.  The response code is obtained from the
222          * prefix+"ResponseCode" execution variable. The response is stored in the
223          * execution where it may be picked up by the Workflow service.
224          * <p>
225          * IMPORTANT: the activity that executes this method should have an
226          * asynchronous continuation after it to ensure the execution variables
227          * are persisted to the database.
228          * <p>
229          * This method is deprecated. Methods that accept a response code should
230          * be used instead.
231          * @param execution the execution
232          * @param errorMessage the error message for the error response
233          */
234         @Deprecated
235         public void buildErrorResponse(Execution execution, String errorMessage) {
236                 buildErrorResponse(execution, errorMessage, null)
237         }
238         // END LEGACY SUPPORT.  TODO: REMOVE THIS CODE
239
240         /**
241          * Builds a response from the specified message content and numeric response
242          * code.  The response code may be an integer or a string representation of
243          * an integer.  The response is stored in the execution where it may be
244          * picked up by the Workflow service.
245          * <p>
246          * IMPORTANT: the activity that executes this method should have an
247          * asynchronous continuation after it to ensure the execution variables
248          * are persisted to the database.
249          * @param execution the execution
250          * @param content the message content
251          * @param responseCode the message response code
252          * @param isSuccess true if this is a success response
253          */
254         @Deprecated
255         protected void buildResponse(Execution execution, String content, Object responseCode,
256                         boolean isSuccess) {
257                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
258
259                 String processKey = getProcessKey(execution);
260                 logDebug("Building " + processKey + " response", isDebugLogEnabled)
261
262                 Map<String, Object> responseMap = new HashMap<String, Object>()
263
264                 if (isSuccess) {
265                         responseMap.put("Status", "Success")
266                 } else {
267                         responseMap.put("Status", "Fail")
268                 }
269
270                 // BEGIN LEGACY SUPPORT.  TODO: REMOVE THIS CODE
271                 def prefix = execution.getVariable("prefix")
272
273                 if (responseCode == null) {
274                         responseCode = execution.getVariable(prefix+"ResponseCode")
275                 } else {
276                         execution.setVariable(prefix+"ResponseCode", String.valueOf(responseCode))
277                 }
278                 // END LEGACY SUPPORT.  TODO: REMOVE THIS CODE
279
280                 responseMap.put("ResponseCode", String.valueOf(responseCode))
281
282                 if (isSuccess) {
283                         responseMap.put("Status", "Success")
284                         // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead
285                         execution.setVariable("WorkflowResponse", content)
286                         // BEGIN LEGACY SUPPORT.  TODO: REMOVE THIS CODE
287                         execution.setVariable(processKey+"Response", content)
288                         execution.setVariable(prefix+"ErrorResponse", null)
289                         // END LEGACY SUPPORT.  TODO: REMOVE THIS CODE
290                 } else {
291                         responseMap.put("Status", "Fail")
292                         // BEGIN LEGACY SUPPORT.  TODO: REMOVE THIS CODE
293                         execution.setVariable(prefix+"ErrorResponse", content)
294                         execution.setVariable(prefix+"Response", null)
295                         // END LEGACY SUPPORT.  TODO: REMOVE THIS CODE
296                 }
297
298                 responseMap.put("Response", content)
299
300                 logDebug(processKey
301                         + " ResponseCode=" + responseMap.get("ResponseCode")
302                         + " Status=" + responseMap.get("Status")
303                         + " Response=\n" + responseMap.get("Response"),
304                         isDebugLogEnabled)
305
306                 execution.setVariable(processKey + "ResponseMap", responseMap)
307         }
308
309         /**
310          * Builds an error response (if one has not already been built) and throws
311          * a BpmnError of type "MSOWorkflowException" that can be caught as a
312          * boundary event.
313          * @param execution the execution
314          * @param errorMessage the error message for the error response
315          * @param responseCode the message response code
316          */
317         @Deprecated
318         public void workflowException(Execution execution, String errorMessage, Object responseCode) {
319                 String processKey = getProcessKey(execution);
320
321                 buildErrorResponse(execution, errorMessage, responseCode)
322                 throw new BpmnError("MSOWorkflowException")
323         }
324
325         /**
326          * Puts a WorkflowException into the execution
327          * @param execution the execution
328          * @param errorCode the error code (normally a 4-digit number)
329          * @param errorMessage the error message
330          */
331         @Deprecated
332         public void newWorkflowException(Execution execution, int errorCode, String errorMessage) {
333                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
334                 String processKey = getProcessKey(execution);
335                 logDebug("Building a " + processKey + " WorkflowException", isDebugLogEnabled)
336
337                 if (errorCode < 1000) {
338                         throw new IllegalArgumentException("ErrorCode must be a number greater than 1000");
339                 }
340
341                 WorkflowException exception = new WorkflowException(processKey, errorCode, errorMessage);
342                 execution.setVariable("WorkflowException", exception);
343         }
344
345         /**
346          * Puts a WorkflowException into the execution and throws an MSOWorkflowException event.
347          * @param execution the execution
348          * @param errorCode the error code (normally a 4-digit number)
349          * @param errorMessage the error message
350          */
351         // TODO: rename this method to be throwWorkflowException
352         @Deprecated
353         public void createWorkflowException(Execution execution, int errorCode, String errorMessage) {
354                 newWorkflowException(execution, errorCode, errorMessage)
355                 throw new BpmnError("MSOWorkflowException", "errorCode:" + errorCode + ", errorMessage:" + errorMessage)
356         }
357
358         /**
359          * Puts a WorkflowException into the execution and throws an MSOWorkflowException event.
360          * @param execution the execution
361          * @param errorCode the error code (normally a 4-digit number)
362          * @param errorMessage the error message
363          */
364         @Deprecated
365         public void commonWorkflowException(Execution execution, int errorCode, String errorMessage) {
366                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
367                 String processKey = getProcessKey(execution);
368                 logDebug("Building a " + processKey + " WorkflowException", isDebugLogEnabled)
369                 logError(errorMessage)
370                 WorkflowException exception = new WorkflowException(processKey, errorCode, errorMessage);
371                 execution.setVariable("WorkflowException", exception);
372                 throw new BpmnError("MSOWorkflowException","errorCode:" + errorCode + ",errorMessage:" + errorMessage)
373         }
374
375         /**
376          * Puts a WorkflowException into the execution and throws an MSOWorkflowException event.
377          * @param execution the execution
378          * @param errorCode the error code (normally a 4-digit number)
379          * @param errorMessage the error message
380          */
381         @Deprecated
382         public void commonWorkflowException(Execution execution, String errorCode, String errorMessage) {
383                 int intRespCode
384                 try{
385                         intRespCode = Integer.parseInt(errorCode)
386                 }catch (Exception e){
387                         intRespCode = 400
388                 }
389                 commonWorkflowException(execution, intRespCode, errorMessage)
390         }
391
392
393
394         /**
395          * Validates that the request exists and that the mso-request-id variable is set.
396          * Additional required variables may be checked by specifying their names.
397          * NOTE: services requiring mso-service-instance-id must specify it explicitly!
398          * If a problem is found, buildAndThrowWorkflowException builds a WorkflowException
399          * and throws an MSOWorkflowException.  This method also sets up the log context for
400          * the workflow.
401          *
402          * @param execution the execution
403          * @return the validated request
404          */
405         public String validateRequest(Execution execution, String... requiredVariables) {
406                 ExceptionUtil exceptionUtil = new ExceptionUtil()
407                 def method = getClass().getSimpleName() + '.validateRequest(' +
408                         'execution=' + execution.getId() +
409                         ', requredVariables=' + requiredVariables +
410                         ')'
411                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
412                 logDebug('Entered ' + method, isDebugLogEnabled)
413
414                 String processKey = getProcessKey(execution)
415                 def prefix = execution.getVariable("prefix")
416
417                 if (prefix == null) {
418                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, processKey + " prefix is null")
419                 }
420
421                 try {
422                         def request = execution.getVariable(prefix + 'Request')
423
424                         if (request == null) {
425                                 request = execution.getVariable(processKey + 'Request')
426
427                                 if (request == null) {
428                                         request = execution.getVariable('bpmnRequest')
429                                 }
430
431                                 setVariable(execution, processKey + 'Request', null)
432                                 setVariable(execution, 'bpmnRequest', null)
433                                 setVariable(execution, prefix + 'Request', request)
434                         }
435
436                         if (request == null) {
437                                 exceptionUtil.buildAndThrowWorkflowException(execution, 1002, processKey + " request is null")
438                         }
439
440                         // All requests must have a request ID.
441                         // Some requests (e.g. SDN-MOBILITY) do not have a service instance ID.
442
443                         String requestId = null
444                         String serviceInstanceId = null
445
446                         List<String> allRequiredVariables = new ArrayList<String>()
447                         allRequiredVariables.add("mso-request-id")
448
449                         if (requiredVariables != null) {
450                                 for (String variable : requiredVariables) {
451                                         if (!allRequiredVariables.contains(variable)) {
452                                                 allRequiredVariables.add(variable)
453                                         }
454                                 }
455                         }
456
457                         for (String variable : allRequiredVariables) {
458                                 def value = execution.getVariable(variable)
459                                 if (value == null || ((value instanceof CharSequence) && value.length() == 0)) {
460                                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, processKey +
461                                                 " request was received with no '" + variable + "' variable")
462                                 }
463
464                                 if ("mso-request-id".equals(variable)) {
465                                         requestId = (String) value
466                                 } else if ("mso-service-instance-id".equals(variable)) {
467                                         serviceInstanceId = (String) value
468                                 }
469                         }
470
471                         if (serviceInstanceId == null) {
472                                 serviceInstanceId = (String) execution.getVariable("mso-service-instance-id")
473                         }
474
475                         utils.logContext(requestId, serviceInstanceId)
476                         logDebug('Incoming message: ' + System.lineSeparator() + request, isDebugLogEnabled)
477                         logDebug('Exited ' + method, isDebugLogEnabled)
478                         return request
479                 } catch (BpmnError e) {
480                         throw e
481                 } catch (Exception e) {
482                         logError('Caught exception in ' + method, e)
483                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, "Invalid Message")
484                 }
485         }
486
487         /**
488          * gets vars stored in a JSON object in prefix+Request and returns as a LazyMap
489          * setting log context here too
490          * @param execution the execution
491          * @return the inputVars
492          */
493         public Map validateJSONReq(Execution execution) {
494                 def method = getClass().getSimpleName() + '.validateJSONReq(' +
495                                 'execution=' + execution.getId() +
496                                 ')'
497                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
498                 logDebug('Entered ' + method, isDebugLogEnabled)
499
500                 String processKey = getProcessKey(execution);
501                 def prefix = execution.getVariable("prefix")
502
503                 def requestId =getVariable(execution, "mso-request-id")
504                 def serviceInstanceId = getVariable(execution, "mso-service-instance-id")
505                 if(requestId!=null && serviceInstanceId!=null){
506                         utils.logContext(requestId, serviceInstanceId)
507                 }
508
509
510                 def request = getVariable(execution, prefix + 'Request')
511
512                 if (request == null) {
513                         request = getVariable(execution, processKey + 'Request')
514
515                         if (request == null) {
516                                 request = getVariable(execution, 'bpmnRequest')
517                         }
518                         execution.setVariable(prefix + 'Request', request)
519                 }
520
521                 def jsonSlurper = new JsonSlurper()
522                 def parsed = jsonSlurper.parseText(request)
523
524
525                 logDebug('Incoming message: ' + System.lineSeparator() + request, isDebugLogEnabled)
526                 logDebug('Exited ' + method, isDebugLogEnabled)
527                 return parsed
528
529         }
530
531
532
533
534         /**
535          * Sends a response to the workflow service that invoked the process.  This method
536          * may only be used by top-level processes that were directly invoked by the
537          * asynchronous workflow service.
538          * @param execution the execution
539          * @param responseCode the response code
540          * @param content the message content
541          * @throws IllegalArgumentException if the response code is invalid
542          *         by HTTP standards
543          * @throws UnsupportedOperationException if not invoked by an asynchronous,
544          *         top-level process
545          * @throws IllegalStateException if a response has already been sent
546          */
547         protected void sendWorkflowResponse(Execution execution, Object responseCode, String response) {
548                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
549                 try {
550                         String processKey = getProcessKey(execution);
551
552                         // isAsyncProcess is injected by the workflow service that started the flow
553                         if (!String.valueOf(execution.getVariable("isAsyncProcess")).equals("true")) {
554                                 throw new UnsupportedOperationException(processKey + ": " +
555                                         "sendWorkflowResponse is valid only in asynchronous workflows");
556                         }
557
558                         if (String.valueOf(execution.getVariable(processKey + "WorkflowResponseSent")).equals("true")) {
559                                         logDebug("Sync response has already been sent for " + processKey, isDebugLogEnabled)
560                         }else{
561
562                                 logDebug("Building " + processKey + " response ", isDebugLogEnabled)
563
564                                 int intResponseCode;
565
566                                 try {
567                                         intResponseCode = Integer.parseInt(String.valueOf(responseCode));
568
569                                         if (intResponseCode < 100 || intResponseCode > 599) {
570                                                 throw new NumberFormatException(String.valueOf(responseCode));
571                                         }
572                                 } catch (NumberFormatException e) {
573                                         throw new IllegalArgumentException("Process " + processKey
574                                                 + " provided an invalid HTTP response code: " + responseCode);
575                                 }
576
577                                 // Only 2XX responses are considered "Success"
578                                 String status = (intResponseCode >= 200 && intResponseCode <= 299) ?
579                                         "Success" : "Fail";
580
581                                 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead
582                                 execution.setVariable(processKey + "ResponseCode", String.valueOf(intResponseCode))
583                                 execution.setVariable(processKey + "Response", response);
584                                 execution.setVariable(processKey + "Status", status);
585                                 execution.setVariable("WorkflowResponse", response)
586
587                                 logDebug("Sending response for " + processKey
588                                         + " ResponseCode=" + intResponseCode
589                                         + " Status=" + status
590                                         + " Response=\n" + response,
591                                         isDebugLogEnabled)
592
593                                 // TODO: ensure that this flow was invoked asynchronously?
594
595                                 WorkflowCallbackResponse callbackResponse = new WorkflowCallbackResponse()
596                                 callbackResponse.setStatusCode(intResponseCode)
597                                 callbackResponse.setMessage(status)
598                                 callbackResponse.setResponse(response)
599
600                                 // TODO: send this data with HTTP POST
601
602                                 WorkflowContextHolder.getInstance().processCallback(
603                                         processKey,
604                                         execution.getProcessInstanceId(),
605                                         execution.getVariable("mso-request-id"),
606                                         callbackResponse)
607
608                                 execution.setVariable(processKey + "WorkflowResponseSent", "true");
609                         }
610
611                 } catch (Exception ex) {
612                         logError("Unable to send workflow response to client ....", ex)
613                 }
614         }
615
616         /**
617          * Returns true if a workflow response has already been sent.
618          * @param execution the execution
619          */
620         protected boolean isWorkflowResponseSent(Execution execution) {
621                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
622                 String processKey = getProcessKey(execution);
623                 return String.valueOf(execution.getVariable(processKey + "WorkflowResponseSent")).equals("true");
624         }
625
626         /**
627          * Returns the process definition key (i.e. the process name) of the
628          * current process.
629          * 
630          * @param execution the execution
631          */
632         public String getProcessKey(Execution execution) {
633                 def testKey = execution.getVariable("testProcessKey")
634                 if(testKey!=null){
635                         return testKey
636                 }
637                 return execution.getProcessEngineServices().getRepositoryService()
638                         .getProcessDefinition(execution.getProcessDefinitionId()).getKey()
639         }
640
641         /**
642          * Returns the process definition key (i.e. the process name) of the
643          * top-level process.
644          * @param execution the execution
645          */
646         public String getMainProcessKey(Execution execution) {
647                 Execution exec = execution
648
649                 while (true) {
650                         Execution parent = exec.getSuperExecution()
651
652                         if (parent == null) {
653                                 parent = exec.getParent()
654
655                                 if (parent == null) {
656                                         break
657                                 }
658                         }
659
660                         exec = parent
661                 }
662
663                 return execution.getProcessEngineServices().getRepositoryService()
664                         .getProcessDefinition(exec.getProcessDefinitionId()).getKey()
665         }
666
667         /**
668          * Gets the node for the named element from the given xml. If the element
669          * does not exist in the xml or is empty, a WorkflowException is created
670          * (and as a result, a MSOWorkflowException event is thrown).
671          *
672          * @param execution The flow's execution.
673          * @param xml Xml to search.
674          * @param elementName Name of element to search for.
675          * @return The element node, if found in the xml.
676          */
677         protected String getRequiredNodeXml(Execution execution, String xml, String elementName) {
678                 def element = utils.getNodeXml(xml, elementName, false)
679                 if (element.trim().isEmpty()) {
680                         def msg = 'Required element \'' + elementName + '\' is missing or empty'
681                         logError(msg)
682                         createWorkflowException(execution, 2000, msg)
683                 } else {
684                         return element
685                 }
686         }
687
688         /**
689          * Gets the value of the named element from the given xml. If the element
690          * does not exist in the xml or is empty, a WorkflowException is created
691          * (and as a result, a MSOWorkflowException event is thrown).
692          *
693          * @param execution The flow's execution.
694          * @param xml Xml to search.
695          * @param elementName Name of element to whose value to get.
696          * @return The value of the element, if found in the xml.
697          */
698         protected String getRequiredNodeText(Execution execution, String xml, String elementName) {
699                 def elementText = utils.getNodeText1(xml, elementName)
700                 if (elementText == null) {
701                         def msg = 'Required element \'' + elementName + '\' is missing or empty'
702                         logError(msg)
703                         createWorkflowException(execution, 2000, msg)
704                 } else {
705                         return elementText
706                 }
707         }
708
709         /**
710          * Get the text for the specified element from the specified xml.  If
711          * the element does not exist, return an empty string.
712          *
713          * @param xml Xml from which to get the element's text.
714          * @param elementName Name of element whose text to get.
715          * @return the element's text or an empty string if the element does not
716          * exist in the given xml.
717          */
718         protected String getNodeTextForce(String xml, String elementName) {
719                 def nodeText = utils.getNodeText1(xml, elementName)
720                 return (nodeText == null) ? '' : nodeText
721         }
722
723         /**
724          * Sends the empty, synchronous response back to the API Handler.
725          * @param execution the execution
726          */
727         @Deprecated
728         public void sendResponse(Execution execution) {
729                 def method = getClass().getSimpleName() + '.sendResponse(' +
730                         'execution=' + execution.getId() +
731                         ')'
732                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
733                 logDebug('Entered ' + method, isDebugLogEnabled)
734
735                 try {
736                         buildResponse(execution, "", 200)
737                         logDebug('Exited ' + method, isDebugLogEnabled)
738                 } catch (BpmnError e) {
739                         throw e;
740                 } catch (Exception e) {
741                         logError('Caught exception in ' + method, e)
742                         workflowException(execution, 'Internal Error', 9999) // TODO: what message and error code?
743                 }
744         }
745
746         /**
747         *Store the variable as typed with java serialization type
748         *@param execution
749         *@param name
750         *@param value
751         */
752         public void setVariable(Execution execution, String name, Object value) {
753                 VariableMap variables = Variables.createVariables()
754                 variables.putValueTyped('payload', Variables.objectValue(value)
755                 .serializationDataFormat(SerializationDataFormats.JAVA) // tells the engine to use java serialization for persisting the value
756                 .create())
757                 execution.setVariable(name,variables)
758         }
759
760         //TODO not sure how this will look in Cockpit
761
762         /**
763          * Returns the variable map
764         *@param execution
765         *@param name
766         *@return
767         **/
768         public String getVariable(Execution execution, String name) {
769                 def myObj = execution.getVariable(name)
770                 if(myObj instanceof VariableMap){
771                         VariableMap serializedObjectMap = (VariableMap) myObj
772                         ObjectValueImpl payloadObj = serializedObjectMap.getValueTyped('payload')
773                         return payloadObj.getValue()
774                 }else{
775                         return myObj
776                 }
777         }
778
779
780         /**
781          * Returns true if a value equals one of the provided set. Equality is
782          * determined by using the equals method if the value object and the
783          * object in the provided set have the same class. Otherwise, the objects
784          * are converted to strings and then compared.  Nulls are permitted for
785          * the value as well as in the provided set
786          * Example:
787          * <pre>
788          *     def statusCode = getStatusCode()
789          *     isOneOf(statusCode, 200, 201, 204)
790          * </pre>
791          * @param value the value to test
792          * @param these a set of permissable values
793          * @return true if the value is in the provided set
794          */
795         public boolean isOneOf(Object value, Object... these) {
796                 for (Object thisOne : these) {
797                         if (thisOne == null) {
798                                 if (value == null) {
799                                         return true
800                                 }
801                         } else {
802                                 if (value != null) {
803                                         if (value.getClass() == thisOne.getClass()) {
804                                                 if (value.equals(thisOne)) {
805                                                         return true
806                                                 }
807                                         } else {
808                                                 if (String.valueOf(value).equals(String.valueOf(thisOne))) {
809                                                         return true
810                                                 }
811                                         }
812                                 }
813                         }
814                 }
815
816                 return false
817         }
818
819         public void setSuccessIndicator(Execution execution, boolean isSuccess) {
820                 String prefix = execution.getVariable('prefix')
821                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
822
823                 logDebug('Entered SetSuccessIndicator Method', isDebugLogEnabled)
824                 execution.setVariable(prefix+'SuccessIndicator', isSuccess)
825                 logDebug('Outgoing SuccessIndicator is: ' + execution.getVariable(prefix+'SuccessIndicator') + '', isDebugLogEnabled)
826         }
827
828
829         public void sendSyncError(Execution execution) {
830                 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
831                 String requestId = execution.getVariable("mso-request-id")
832                 logDebug('sendSyncError, requestId: ' + requestId, isDebugEnabled)
833                 WorkflowException workflowExceptionObj = execution.getVariable("WorkflowException")
834                 if (workflowExceptionObj != null) {
835                         String errorMessage = workflowExceptionObj.getErrorMessage()
836                         def errorCode = workflowExceptionObj.getErrorCode()
837                         logDebug('sendSyncError, requestId: '  + requestId + ' | errorMessage: ' + errorMessage + ' | errorCode: ' + errorCode, isDebugEnabled)
838                         sendWorkflowResponse(execution, errorCode, errorMessage)
839                 }
840         }
841         
842         /**
843          * Create a WorkflowException - uses ExceptionUtil to build a WorkflowException
844          * @param execution
845          * @param errorCode
846          * @param errorMessage
847          * @param isDebugEnabled
848          */
849         public void buildWorkflowException(Execution execution, int errorCode, String errorMessage, boolean isDebugEnabled) {
850                 (new ExceptionUtil()).buildWorkflowException(execution, errorCode, errorMessage)
851         }
852         
853         /**
854          * Executes a named groovy script method in the current object
855          */
856         public void executeMethod(String methodName, Object... args) {
857                 
858                 if (args != null && args.size() > 0) {
859                         
860                         // First argument of method to call is always the execution object
861                         Execution execution = (Execution) args[0]
862
863                         def classAndMethod = getClass().getSimpleName() + '.' + methodName + '(execution=' + execution.getId() + ')'
864                         def isDebugEnabled =  execution.getVariable('isDebugLogEnabled')
865
866                         logDebug('Entered ' + classAndMethod, isDebugEnabled)
867                         logDebug('Received parameters: ' + args, isDebugEnabled)
868
869                         try{
870                                 def methodToCall = this.metaClass.getMetaMethod(methodName, args)
871                                 logDebug('Method to call: ' + methodToCall, isDebugEnabled)
872                                 methodToCall?.invoke(this, args)
873                         }
874                         catch(BpmnError bpmnError) {
875                                 logDebug('Rethrowing BpmnError ' + bpmnError.getMessage(), isDebugEnabled)
876                                 throw bpmnError
877                         }
878                         catch(Exception e) {
879                                 e.printStackTrace()
880                                 logDebug('Unexpected error encountered - ' + e.getMessage(), isDebugEnabled)
881                                 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
882                         }
883                         finally {
884                                 logDebug('Exited ' + classAndMethod, isDebugEnabled)
885                         }
886                 }
887         }
888         
889         /**
890          *This method determines and adds the appropriate ending to come
891          *after a number (-st, -nd, -rd, or -th)
892          *
893          *@param int n
894          *
895          *@return String ending - number with suffix
896          */
897
898         public static String labelMaker(Object n) {
899                 Integer num
900                 if(n instanceof String){
901                         num = Integer.parseInt(n)
902                 }else{
903                         num = n
904                 }
905
906                 String ending = ""; //the end to be added to the number
907                 if(num != null){
908                         if ((num % 10 == 1) && (num != 11)) {
909                                 ending = num + "st";
910                         } else if ((num % 10 == 2) && (num != 12)) {
911                                 ending = num + "nd";
912                         } else if ((num % 10 == 3) && (num != 13)) {
913                                 ending = num + "rd";
914                         } else {
915                                 ending = num + "th";
916                         }
917                 }
918                 return ending
919         }
920
921         /**
922          *
923          *This method gets and decodes SDNC Response's "RequestData".
924          *
925          *@param response - the sdnc response
926          *
927          *@return data - the response "RequestData" decoded
928          *
929          */
930         public String getRequestDataDecoded(String response){
931                 String data = utils.getNodeText1(response, "RequestData")
932                 if(data != null){
933                         data = data.replaceAll("&lt;", "<")
934                         data = data.replaceAll("&gt;", ">")
935                 }
936
937                 return data
938         }
939
940
941         /**
942          * Constructs a workflow message callback URL for the specified message type and correlator.
943          * @param messageType the message type (e.g. SDNCAResponse or VNFAResponse)
944          * @param correlator the correlator value (e.g. a request ID)
945          */
946         public String createCallbackURL(Execution execution, String messageType, String correlator) {
947                 String endpoint = (String) execution.getVariable('URN_mso_workflow_message_endpoint')
948
949                 if (endpoint == null || endpoint.isEmpty()) {
950                         ExceptionUtil exceptionUtil = new ExceptionUtil()
951                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000,
952                                 'mso:workflow:message:endpoint URN mapping is not set')
953                 }
954
955                 while (endpoint.endsWith('/')) {
956                         endpoint = endpoint.substring(0, endpoint.length()-1)
957                 }
958
959                 return endpoint +
960                         '/' + UriUtils.encodePathSegment(messageType, 'UTF-8') +
961                         '/' + UriUtils.encodePathSegment(correlator, 'UTF-8')
962         }
963
964 }