Replaced all tabs with spaces in java and pom.xml
[so.git] / bpmn / MSOCoreBPMN / src / main / java / org / onap / so / 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.onap.so.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 import org.onap.so.bpmn.core.internal.VariableNameExtractor;
27
28 /**
29  * Base class for service tasks.
30  */
31 public class BaseTask implements JavaDelegate {
32
33     /**
34      * Get the value of a required field. This method throws MissingInjectedFieldException if the expression is null,
35      * and BadInjectedFieldException if the expression evaluates to a null value.
36      *
37      * @param expression the expression
38      * @param execution the execution
39      * @param fieldName the field name (for logging and exceptions)
40      * @return the field value
41      */
42     protected Object getField(Expression expression, DelegateExecution execution, String fieldName) {
43         return getFieldImpl(expression, execution, fieldName, false);
44     }
45
46     /**
47      * Gets the value of an optional field. There are three conditions in which this method returns null:
48      * <p>
49      * <ol>
50      * <li>The expression itself is null (i.e. the field is missing altogether.</li>
51      * <li>The expression evaluates to a null value.</li>
52      * <li>The expression references a single variable which has not been set.</li>
53      * </ol>
54      * <p>
55      * Examples:<br>
56      * Expression ${x} when x is null: return null<br>
57      * Expression ${x} when x is unset: return null<br>
58      * Expression ${x+y} when x and/or y are unset: exception<br>
59      *
60      * @param expression the expression
61      * @param execution the execution
62      * @param fieldName the field name (for logging and exceptions)
63      * @return the field value, possibly null
64      */
65     protected Object getOptionalField(Expression expression, DelegateExecution execution, String fieldName) {
66         return getFieldImpl(expression, execution, fieldName, true);
67     }
68
69     /**
70      * Get the value of a required output variable field. This method throws MissingInjectedFieldException if the
71      * expression is null, and BadInjectedFieldException if the expression produces a null or illegal variable name.
72      * Legal variable names contain only letters, numbers, and the underscore character ('_').
73      *
74      * @param expression the expression
75      * @param execution the execution
76      * @param fieldName the field name (for logging and exceptions)
77      * @return the output variable name
78      */
79     protected String getOutputField(Expression expression, DelegateExecution execution, String fieldName) {
80         Object o = getFieldImpl(expression, execution, fieldName, false);
81         if (o instanceof String) {
82             String variable = (String) o;
83             if (!isLegalVariable(variable)) {
84                 throw new BadInjectedFieldException(fieldName, getTaskName(),
85                         "'" + variable + "' is not a legal variable name");
86             }
87             return variable;
88         } else {
89             throw new BadInjectedFieldException(fieldName, getTaskName(),
90                     "expected a variable name string" + ", got object of type " + o.getClass().getName());
91         }
92     }
93
94     /**
95      * Get the value of an optional output variable field. This method throws BadInjectedFieldException if the
96      * expression produces an illegal variable name. Legal variable names contain only letters, numbers, and the
97      * underscore character ('_').
98      *
99      * @param expression the expression
100      * @param execution the execution
101      * @param fieldName the field name (for logging and exceptions)
102      * @return the output variable name, possibly null
103      */
104     protected String getOptionalOutputField(Expression expression, DelegateExecution execution, String fieldName) {
105         Object o = getFieldImpl(expression, execution, fieldName, true);
106         if (o instanceof String) {
107             String variable = (String) o;
108             if (!isLegalVariable(variable)) {
109                 throw new BadInjectedFieldException(fieldName, getTaskName(),
110                         "'" + variable + "' is not a legal variable name");
111             }
112             return variable;
113         } else if (o == null) {
114             return null;
115         } else {
116             throw new BadInjectedFieldException(fieldName, getTaskName(),
117                     "expected a variable name string" + ", got object of type " + o.getClass().getName());
118         }
119     }
120
121     /**
122      * Get the value of a required string field. This method throws MissingInjectedFieldException if the expression is
123      * null, and BadInjectedFieldException if the expression evaluates to a null value.
124      * <p>
125      * Note: the result is coerced to a string value, if necessary.
126      *
127      * @param expression the expression
128      * @param execution the execution
129      * @param fieldName the field name (for logging and exceptions)
130      * @return the field value
131      */
132     protected String getStringField(Expression expression, DelegateExecution execution, String fieldName) {
133         Object o = getFieldImpl(expression, execution, fieldName, false);
134         if (o instanceof String) {
135             return (String) o;
136         } else {
137             throw new BadInjectedFieldException(fieldName, getTaskName(),
138                     "cannot convert '" + o.toString() + "' to Integer");
139         }
140     }
141
142     /**
143      * Gets the value of an optional string field. There are three conditions in which this method returns null:
144      * <p>
145      * <ol>
146      * <li>The expression itself is null (i.e. the field is missing altogether.</li>
147      * <li>The expression evaluates to a null value.</li>
148      * <li>The expression references a single variable which has not been set.</li>
149      * </ol>
150      * <p>
151      * Examples:<br>
152      * Expression ${x} when x is null: return null<br>
153      * Expression ${x} when x is unset: return null<br>
154      * Expression ${x+y} when x and/or y are unset: exception<br>
155      * <p>
156      * Note: the result is coerced to a string value, if necessary.
157      *
158      * @param expression the expression
159      * @param execution the execution
160      * @param fieldName the field name (for logging and exceptions)
161      * @return the field value, possibly null
162      */
163     protected String getOptionalStringField(Expression expression, DelegateExecution execution, String fieldName) {
164         Object o = getFieldImpl(expression, execution, fieldName, true);
165         if (o instanceof String) {
166             return (String) o;
167         } else if (o == null) {
168             return null;
169         } else {
170             return o.toString();
171         }
172     }
173
174     /**
175      * Get the value of a required integer field. This method throws MissingInjectedFieldException if the expression is
176      * null, and BadInjectedFieldException if the expression evaluates to a null value or a value that cannot be coerced
177      * to an integer.
178      *
179      * @param expression the expression
180      * @param execution the execution
181      * @param fieldName the field name (for logging and exceptions)
182      * @return the field value
183      */
184     protected Integer getIntegerField(Expression expression, DelegateExecution execution, String fieldName) {
185         Object o = getFieldImpl(expression, execution, fieldName, false);
186         if (o instanceof Integer) {
187             return (Integer) o;
188         } else {
189             try {
190                 return Integer.parseInt(o.toString());
191             } catch (NumberFormatException e) {
192                 throw new BadInjectedFieldException(fieldName, getTaskName(),
193                         "cannot convert '" + o.toString() + "' to Integer");
194             }
195         }
196     }
197
198     /**
199      * Gets the value of an optional integer field. There are three conditions in which this method returns null:
200      * <p>
201      * <ol>
202      * <li>The expression itself is null (i.e. the field is missing altogether.</li>
203      * <li>The expression evaluates to a null value.</li>
204      * <li>The expression references a single variable which has not been set.</li>
205      * </ol>
206      * <p>
207      * Examples:<br>
208      * Expression ${x} when x is null: return null<br>
209      * Expression ${x} when x is unset: return null<br>
210      * Expression ${x+y} when x and/or y are unset: exception<br>
211      * <p>
212      * Note: the result is coerced to an integer value, if necessary. This method throws BadInjectedFieldException if
213      * the result cannot be coerced to an integer.
214      *
215      * @param expression the expression
216      * @param execution the execution
217      * @param fieldName the field name (for logging and exceptions)
218      * @return the field value, possibly null
219      */
220     protected Integer getOptionalIntegerField(Expression expression, DelegateExecution execution, String fieldName) {
221         Object o = getFieldImpl(expression, execution, fieldName, true);
222         if (o instanceof Integer) {
223             return (Integer) o;
224         } else if (o == null) {
225             return null;
226         } else {
227             try {
228                 return Integer.parseInt(o.toString());
229             } catch (NumberFormatException e) {
230                 throw new BadInjectedFieldException(fieldName, getTaskName(),
231                         "cannot convert '" + o.toString() + "' to Integer");
232             }
233         }
234     }
235
236     /**
237      * Gets the value of an optional long field. There are three conditions in which this method returns null:
238      * <p>
239      * <ol>
240      * <li>The expression itself is null (i.e. the field is missing altogether.</li>
241      * <li>The expression evaluates to a null value.</li>
242      * <li>The expression references a single variable which has not been set.</li>
243      * </ol>
244      * <p>
245      * Examples:<br>
246      * Expression ${x} when x is null: return null<br>
247      * Expression ${x} when x is unset: return null<br>
248      * Expression ${x+y} when x and/or y are unset: exception<br>
249      * <p>
250      * Note: the result is coerced to a long value, if necessary. This method throws BadInjectedFieldException if the
251      * result cannot be coerced to a long.
252      *
253      * @param expression the expression
254      * @param execution the execution
255      * @param fieldName the field name (for logging and exceptions)
256      * @return the field value, possibly null
257      */
258     protected Long getOptionalLongField(Expression expression, DelegateExecution execution, String fieldName) {
259         Object o = getFieldImpl(expression, execution, fieldName, true);
260         if (o instanceof Long) {
261             return (Long) o;
262         } else if (o == null) {
263             return null;
264         } else {
265             try {
266                 return Long.parseLong(o.toString());
267             } catch (NumberFormatException e) {
268                 throw new BadInjectedFieldException(fieldName, getTaskName(),
269                         "cannot convert '" + o.toString() + "' to Long");
270             }
271         }
272     }
273
274     /**
275      * Get the value of a required long field. This method throws MissingInjectedFieldException if the expression is
276      * null, and BadInjectedFieldException if the expression evaluates to a null value or a value that cannot be coerced
277      * to a long.
278      *
279      * @param expression the expression
280      * @param execution the execution
281      * @param fieldName the field name (for logging and exceptions)
282      * @return the field value
283      */
284     protected Long getLongField(Expression expression, DelegateExecution execution, String fieldName) {
285         Object o = getFieldImpl(expression, execution, fieldName, false);
286         if (o instanceof Long) {
287             return (Long) o;
288         } else {
289             try {
290                 return Long.parseLong(o.toString());
291             } catch (NumberFormatException e) {
292                 throw new BadInjectedFieldException(fieldName, getTaskName(),
293                         "cannot convert '" + o.toString() + "' to Long");
294             }
295         }
296     }
297
298     /**
299      * Common implementation for field "getter" methods.
300      *
301      * @param expression the expression
302      * @param execution the execution
303      * @param fieldName the field name (for logging and exceptions)
304      * @param optional true if the field is optional
305      * @return the field value, possibly null
306      */
307     private Object getFieldImpl(Expression expression, DelegateExecution execution, String fieldName,
308             boolean optional) {
309         if (expression == null) {
310             if (!optional) {
311                 throw new MissingInjectedFieldException(fieldName, getTaskName());
312             }
313             return null;
314         }
315
316         Object value = null;
317
318         try {
319             value = expression.getValue(execution);
320         } catch (Exception e) {
321             if (!optional) {
322                 throw new BadInjectedFieldException(fieldName, getTaskName(), e.getClass().getSimpleName(), e);
323             }
324
325             // At this point, we have an exception that occurred while
326             // evaluating an expression for an optional field. A common
327             // problem is that the expression is a simple reference to a
328             // variable which has never been set, e.g. the expression is
329             // ${x}. The normal activiti behavior is to throw an exception,
330             // but we don't like that, so we have the following workaround,
331             // which parses the expression text to see if it is a "simple"
332             // variable reference, and if so, returns null. If the
333             // expression is anything other than a single variable
334             // reference, then an exception is thrown, as it would have
335             // been without this workaround.
336
337             // Get the expression text so we can parse it
338             String s = expression.getExpressionText();
339             new VariableNameExtractor(s).extract().ifPresent(name -> {
340                 if (execution.hasVariable(name)) {
341                     throw new BadInjectedFieldException(fieldName, getTaskName(), e.getClass().getSimpleName(), e);
342                 }
343             });
344         }
345
346         if (value == null && !optional) {
347             throw new BadInjectedFieldException(fieldName, getTaskName(), "required field has null value");
348         }
349
350         return value;
351     }
352
353     /**
354      * Tests if a character is a "word" character.
355      *
356      * @param c the character
357      * @return true if the character is a "word" character.
358      */
359     private static boolean isWordCharacter(char c) {
360         return (Character.isLetterOrDigit(c) || c == '_');
361     }
362
363     /**
364      * Tests if the specified string is a legal flow variable name.
365      *
366      * @param name the string
367      * @return true if the string is a legal flow variable name
368      */
369     private boolean isLegalVariable(String name) {
370         if (name == null) {
371             return false;
372         }
373
374         int len = name.length();
375
376         if (len == 0) {
377             return false;
378         }
379
380         char c = name.charAt(0);
381
382         if (!Character.isLetter(c) && c != '_') {
383             return false;
384         }
385
386         for (int i = 1; i < len; i++) {
387             c = name.charAt(i);
388             if (!Character.isLetterOrDigit(c) && c != '_') {
389                 return false;
390             }
391         }
392
393         return true;
394     }
395
396     /**
397      * Returns the name of the task (normally the java class name).
398      *
399      * @return the name of the task
400      */
401     public String getTaskName() {
402         return getClass().getSimpleName();
403     }
404
405     @Override
406     public void execute(DelegateExecution execution) throws Exception {}
407 }