Change the header to SO
[so.git] / bpmn / MSOCoreBPMN / src / main / java / org / openecomp / mso / bpmn / core / BaseTask.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
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.core;
22
23 import org.camunda.bpm.engine.delegate.DelegateExecution;
24 import org.camunda.bpm.engine.delegate.Expression;
25 import org.camunda.bpm.engine.delegate.JavaDelegate;
26
27 /**
28  * Base class for service tasks.
29  */
30 public class BaseTask implements JavaDelegate {
31
32         /**
33          * Get the value of a required field.  This method throws
34          * MissingInjectedFieldException if the expression is null, and
35          * BadInjectedFieldException if the expression evaluates to a null
36          * value.
37          *
38          * @param expression the expression
39          * @param execution the execution
40          * @param fieldName the field name (for logging and exceptions)
41          * @return the field value
42          */
43         protected Object getField(Expression expression,
44                         DelegateExecution execution, String fieldName) {
45                 return getFieldImpl(expression, execution, fieldName, false);
46         }
47         
48         /**
49          * Gets the value of an optional field.  There are three conditions
50          * in which this method returns null:
51          * <p>
52          * <ol>
53          * <li> The expression itself is null (i.e. the field is missing
54          * altogether.</li>
55          * <li>The expression evaluates to a null value.</li>
56          * <li>The expression references a single variable which has not
57          * been set.</li>
58          * </ol>
59          * <p>
60          * Examples:<br>
61          * Expression ${x} when x is null: return null<br>
62          * Expression ${x} when x is unset: return null<br>
63          * Expression ${x+y} when x and/or y are unset: exception<br>
64          * 
65          * @param expression the expression
66          * @param execution the execution
67          * @param fieldName the field name (for logging and exceptions)
68          * @return the field value, possibly null
69          */
70         protected Object getOptionalField(Expression expression,
71                         DelegateExecution execution, String fieldName) {
72                 return getFieldImpl(expression, execution, fieldName, true);
73         }
74         
75         /**
76          * Get the value of a required output variable field. This method
77          * throws MissingInjectedFieldException if the expression is null, and
78          * BadInjectedFieldException if the expression produces a null or
79          * illegal variable name.  Legal variable names contain only letters,
80          * numbers, and the underscore character ('_').
81          *
82          * @param expression the expression
83          * @param execution the execution
84          * @param fieldName the field name (for logging and exceptions)
85          * @return the output variable name
86          */
87         protected String getOutputField(Expression expression,
88                         DelegateExecution execution, String fieldName) {
89                 Object o = getFieldImpl(expression, execution, fieldName, false);
90                 if (o instanceof String) {
91                         String variable = (String) o;
92                         if (!isLegalVariable(variable)) {
93                                 throw new BadInjectedFieldException(
94                                         fieldName, getTaskName(), "'" + variable
95                                                 + "' is not a legal variable name");
96                         }
97                         return variable;
98                 } else {
99                         throw new BadInjectedFieldException(
100                                 fieldName, getTaskName(), "expected a variable name string"
101                                         + ", got object of type " + o.getClass().getName());
102                 }
103         }
104         
105         /**
106          * Get the value of an optional output variable field. This method
107          * throws BadInjectedFieldException if the expression produces an illegal
108          * variable name.  Legal variable names contain only letters, numbers,
109          * and the underscore character ('_').
110          * 
111          * @param expression the expression
112          * @param execution the execution
113          * @param fieldName the field name (for logging and exceptions)
114          * @return the output variable name, possibly null
115          */
116         protected String getOptionalOutputField(Expression expression,
117                         DelegateExecution execution, String fieldName) {
118                 Object o = getFieldImpl(expression, execution, fieldName, true);
119                 if (o instanceof String) {
120                         String variable = (String) o;
121                         if (!isLegalVariable(variable)) {
122                                 throw new BadInjectedFieldException(
123                                         fieldName, getTaskName(), "'" + variable
124                                                 + "' is not a legal variable name");
125                         }
126                         return variable;
127                 } else if (o == null) {
128                         return null;
129                 } else {
130                         throw new BadInjectedFieldException(
131                                 fieldName, getTaskName(), "expected a variable name string"
132                                         + ", got object of type " + o.getClass().getName());
133                 }
134         }
135
136         /**
137          * Get the value of a required string field.  This method throws
138          * MissingInjectedFieldException if the expression is null, and
139          * BadInjectedFieldException if the expression evaluates to a null
140          * value.
141          * <p>
142          * Note: the result is coerced to a string value, if necessary.
143          *
144          * @param expression the expression
145          * @param execution the execution
146          * @param fieldName the field name (for logging and exceptions)
147          * @return the field value
148          */
149         protected String getStringField(Expression expression,
150                         DelegateExecution execution, String fieldName) {
151                 Object o = getFieldImpl(expression, execution, fieldName, false);
152                 if (o instanceof String) {
153                         return (String) o;
154                 } else {
155                         throw new BadInjectedFieldException(
156                                 fieldName, getTaskName(), "cannot convert '" + o.toString()
157                                 + "' to Integer");
158                 }
159         }
160         
161         /**
162          * Gets the value of an optional string field.  There are three conditions
163          * in which this method returns null:
164          * <p>
165          * <ol>
166          * <li> The expression itself is null (i.e. the field is missing
167          * altogether.</li>
168          * <li>The expression evaluates to a null value.</li>
169          * <li>The expression references a single variable which has not
170          * been set.</li>
171          * </ol>
172          * <p>
173          * Examples:<br>
174          * Expression ${x} when x is null: return null<br>
175          * Expression ${x} when x is unset: return null<br>
176          * Expression ${x+y} when x and/or y are unset: exception<br>
177          * <p>
178          * Note: the result is coerced to a string value, if necessary.
179          * 
180          * @param expression the expression
181          * @param execution the execution
182          * @param fieldName the field name (for logging and exceptions)
183          * @return the field value, possibly null
184          */
185         protected String getOptionalStringField(Expression expression,
186                         DelegateExecution execution, String fieldName) {
187                 Object o = getFieldImpl(expression, execution, fieldName, true);
188                 if (o instanceof String) {
189                         return (String) o;
190                 } else if (o == null) {
191                         return null;
192                 } else {
193                         return o.toString();
194                 }
195         }
196         
197         /**
198          * Get the value of a required integer field. This method throws
199          * MissingInjectedFieldException if the expression is null, and
200          * BadInjectedFieldException if the expression evaluates to a null
201          * value or a value that cannot be coerced to an integer.
202          *
203          * @param expression the expression
204          * @param execution the execution
205          * @param fieldName the field name (for logging and exceptions)
206          * @return the field value
207          */
208         protected Integer getIntegerField(Expression expression,
209                         DelegateExecution execution, String fieldName) {
210                 Object o = getFieldImpl(expression, execution, fieldName, false);
211                 if (o instanceof Integer) {
212                         return (Integer) o;
213                 } else {
214                         try {
215                                 return Integer.parseInt(o.toString());
216                         } catch (NumberFormatException e) {
217                                 throw new BadInjectedFieldException(
218                                         fieldName, getTaskName(), "cannot convert '" + o.toString()
219                                         + "' to Integer");
220                         }
221                 }
222         }
223         
224         /**
225          * Gets the value of an optional integer field.  There are three conditions
226          * in which this method returns null:
227          * <p>
228          * <ol>
229          * <li> The expression itself is null (i.e. the field is missing
230          * altogether.</li>
231          * <li>The expression evaluates to a null value.</li>
232          * <li>The expression references a single variable which has not
233          * been set.</li>
234          * </ol>
235          * <p>
236          * Examples:<br>
237          * Expression ${x} when x is null: return null<br>
238          * Expression ${x} when x is unset: return null<br>
239          * Expression ${x+y} when x and/or y are unset: exception<br>
240          * <p>
241          * Note: the result is coerced to an integer value, if necessary. This
242          * method throws BadInjectedFieldException if the result cannot be coerced
243          * to an integer.
244          * 
245          * @param expression the expression
246          * @param execution the execution
247          * @param fieldName the field name (for logging and exceptions)
248          * @return the field value, possibly null
249          */
250         protected Integer getOptionalIntegerField(Expression expression,
251                         DelegateExecution execution, String fieldName) {
252                 Object o = getFieldImpl(expression, execution, fieldName, true);
253                 if (o instanceof Integer) {
254                         return (Integer) o;
255                 } else if (o == null) {
256                         return null;
257                 } else {
258                         try {
259                                 return Integer.parseInt(o.toString());
260                         } catch (NumberFormatException e) {
261                                 throw new BadInjectedFieldException(
262                                         fieldName, getTaskName(), "cannot convert '" + o.toString()
263                                         + "' to Integer");
264                         }
265                 }
266         }
267         
268         /**
269          * Gets the value of an optional long field.  There are three conditions
270          * in which this method returns null:
271          * <p>
272          * <ol>
273          * <li> The expression itself is null (i.e. the field is missing
274          * altogether.</li>
275          * <li>The expression evaluates to a null value.</li>
276          * <li>The expression references a single variable which has not
277          * been set.</li>
278          * </ol>
279          * <p>
280          * Examples:<br>
281          * Expression ${x} when x is null: return null<br>
282          * Expression ${x} when x is unset: return null<br>
283          * Expression ${x+y} when x and/or y are unset: exception<br>
284          * <p>
285          * Note: the result is coerced to a long value, if necessary. This
286          * method throws BadInjectedFieldException if the result cannot be coerced
287          * to a long.
288          * 
289          * @param expression the expression
290          * @param execution the execution
291          * @param fieldName the field name (for logging and exceptions)
292          * @return the field value, possibly null
293          */
294         protected Long getOptionalLongField(Expression expression,
295                         DelegateExecution execution, String fieldName) {
296                 Object o = getFieldImpl(expression, execution, fieldName, true);
297                 if (o instanceof Long) {
298                         return (Long) o;
299                 } else if (o == null) {
300                         return null;
301                 } else {
302                         try {
303                                 return Long.parseLong(o.toString());
304                         } catch (NumberFormatException e) {
305                                 throw new BadInjectedFieldException(
306                                         fieldName, getTaskName(), "cannot convert '" + o.toString()
307                                         + "' to Long");
308                         }
309                 }
310         }
311         
312         /**
313          * Get the value of a required long field. This method throws
314          * MissingInjectedFieldException if the expression is null, and
315          * BadInjectedFieldException if the expression evaluates to a null
316          * value or a value that cannot be coerced to a long.
317          *
318          * @param expression the expression
319          * @param execution the execution
320          * @param fieldName the field name (for logging and exceptions)
321          * @return the field value
322          */
323         protected Long getLongField(Expression expression,
324                         DelegateExecution execution, String fieldName) {
325                 Object o = getFieldImpl(expression, execution, fieldName, false);
326                 if (o instanceof Long) {
327                         return (Long) o;
328                 } else {
329                         try {
330                                 return Long.parseLong(o.toString());
331                         } catch (NumberFormatException e) {
332                                 throw new BadInjectedFieldException(
333                                         fieldName, getTaskName(), "cannot convert '" + o.toString()
334                                         + "' to Long");
335                         }
336                 }
337         }
338
339         /**
340          * Common implementation for field "getter" methods.
341          * @param expression the expression
342          * @param execution the execution
343          * @param fieldName the field name (for logging and exceptions)
344          * @param optional true if the field is optional
345          * @return the field value, possibly null
346          */
347         private Object getFieldImpl(Expression expression,
348                         DelegateExecution execution, String fieldName, boolean optional) {
349                 if (expression == null) {
350                         if (!optional) {
351                                 throw new MissingInjectedFieldException(
352                                         fieldName, getTaskName());
353                         }
354                         return null;
355                 }
356
357                 Object value;
358
359                 try {
360                         value = expression.getValue(execution);
361                 } catch (Exception e) {
362                         if (!optional) {
363                                 throw new BadInjectedFieldException(
364                                         fieldName, getTaskName(), e.getClass().getSimpleName(), e);
365                         }
366
367                         // At this point, we have an exception that occurred while
368                         // evaluating an expression for an optional field. A common 
369                         // problem is that the expression is a simple reference to a
370                         // variable which has never been set, e.g. the expression is
371                         // ${x}. The normal activiti behavior is to throw an exception,
372                         // but we don't like that, so we have the following workaround,
373                         // which parses the expression text to see if it is a "simple"
374                         // variable reference, and if so, returns null.  If the
375                         // expression is anything other than a single variable
376                         // reference, then an exception is thrown, as it would have
377                         // been without this workaround.
378
379                         // Get the expression text so we can parse it
380                         String s = expression.getExpressionText();
381
382 //                      if (isDebugEnabled(execution)) {
383 //                              logDebug(execution, getTaskName() + " field '" + fieldName
384 //                                      + "' expression evaluation failed: " + s);
385 //                      }
386
387                         int len = s.length();
388                         int i = 0;
389
390                         // Skip whitespace
391                         while (i < len && Character.isWhitespace(s.charAt(i))) {
392                                 i++;
393                         }
394
395                         // Next character must be '$'
396                         if (i == len || s.charAt(i++) != '$') {
397                                 throw new BadInjectedFieldException(
398                                         fieldName, getTaskName(), e.getClass().getSimpleName(), e);
399                         }
400
401                         // Skip whitespace
402                         while (i < len && Character.isWhitespace(s.charAt(i))) {
403                                 i++;
404                         }
405
406                         // Next character must be '{'
407                         if (i == len || s.charAt(i++) != '{') {
408                                 throw new BadInjectedFieldException(
409                                         fieldName, getTaskName(), e.getClass().getSimpleName(), e);
410                         }
411
412                         // Skip whitespace
413                         while (i < len && Character.isWhitespace(s.charAt(i))) {
414                                 i++;
415                         }
416
417                         // Collect the variable name
418                         StringBuilder variable = new StringBuilder();
419                         while (i < len && isWordCharacter(s.charAt(i))) {
420                                 variable.append(s.charAt(i));
421                                 i++;
422                         }
423
424                         if (variable.length() == 0) {
425                                 throw new BadInjectedFieldException(
426                                         fieldName, getTaskName(), e.getClass().getSimpleName(), e);
427                         }
428
429                         // Skip whitespace
430                         while (i < len && Character.isWhitespace(s.charAt(i))) {
431                                 i++;
432                         }
433
434                         // Next character must be '}'
435                         if (i == len || s.charAt(i++) != '}') {
436                                 throw new BadInjectedFieldException(
437                                         fieldName, getTaskName(), e.getClass().getSimpleName(), e);
438                         }
439
440                         // Skip whitespace
441                         while (i < len && Character.isWhitespace(s.charAt(i))) {
442                                 i++;
443                         }
444
445                         // Must be at end of string
446                         if (i != len) {
447                                 throw new BadInjectedFieldException(
448                                         fieldName, getTaskName(), e.getClass().getSimpleName(), e);
449                         }
450
451 //                      if (isDebugEnabled(execution)) {
452 //                              logDebug(execution, "Checking if variable '"
453 //                                      + variable.toString() + "' exists");
454 //                      }
455
456                         // If the variable exists then the problem was
457                         // something else...
458                         if (execution.hasVariable(variable.toString())) {
459                                 throw new BadInjectedFieldException(
460                                         fieldName, getTaskName(), e.getClass().getSimpleName(), e);
461                         }
462
463                         // The variable doesn't exist.
464
465 //                      if (isDebugEnabled(execution)) {
466 //                              logDebug(execution, "Variable '" + variable.toString()
467 //                                      + "' does not exist [ok]");
468 //                      }
469
470                         value = null;
471                 }
472
473                 if (value == null && !optional) {
474                         throw new BadInjectedFieldException(
475                                 fieldName, getTaskName(), "required field has null value");
476                 }
477         
478                 return value;
479         }
480         
481         /**
482          * Tests if a character is a "word" character.
483          * @param c the character
484          * @return true if the character is a "word" character.
485          */
486         private boolean isWordCharacter(char c) {
487                 return (Character.isLetterOrDigit(c) || c == '_');
488         }
489         
490         /**
491          * Tests if the specified string is a legal flow variable name.
492          * @param name the string
493          * @return true if the string is a legal flow variable name
494          */
495         private boolean isLegalVariable(String name) {
496                 if (name == null) {
497                         return false;
498                 }
499
500                 int len = name.length();
501
502                 if (len == 0) {
503                         return false;
504                 }
505
506                 char c = name.charAt(0);
507
508                 if (!Character.isLetter(c) && c != '_') {
509                         return false;
510                 }
511
512                 for (int i = 1; i < len; i++) {
513                         c = name.charAt(i);
514                         if (!Character.isLetterOrDigit(c) && c != '_') {
515                                 return false;
516                         }
517                 }
518
519                 return true;
520         }
521         
522         /**
523          * Returns the name of the task (normally the java class name).
524          * @return the name of the task
525          */
526         public String getTaskName() {
527                 return getClass().getSimpleName();
528         }
529
530         @Override
531         public void execute(DelegateExecution execution) throws Exception {     }
532 }