2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.so.bpmn.core;
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;
29 * Base class for service tasks.
31 public class BaseTask implements JavaDelegate {
34 * Get the value of a required field. This method throws
35 * MissingInjectedFieldException if the expression is null, and
36 * BadInjectedFieldException if the expression evaluates to a null
39 * @param expression the expression
40 * @param execution the execution
41 * @param fieldName the field name (for logging and exceptions)
42 * @return the field value
44 protected Object getField(Expression expression,
45 DelegateExecution execution, String fieldName) {
46 return getFieldImpl(expression, execution, fieldName, false);
50 * Gets the value of an optional field. There are three conditions
51 * in which this method returns null:
54 * <li> The expression itself is null (i.e. the field is missing
56 * <li>The expression evaluates to a null value.</li>
57 * <li>The expression references a single variable which has not
62 * Expression ${x} when x is null: return null<br>
63 * Expression ${x} when x is unset: return null<br>
64 * Expression ${x+y} when x and/or y are unset: exception<br>
66 * @param expression the expression
67 * @param execution the execution
68 * @param fieldName the field name (for logging and exceptions)
69 * @return the field value, possibly null
71 protected Object getOptionalField(Expression expression,
72 DelegateExecution execution, String fieldName) {
73 return getFieldImpl(expression, execution, fieldName, true);
77 * Get the value of a required output variable field. This method
78 * throws MissingInjectedFieldException if the expression is null, and
79 * BadInjectedFieldException if the expression produces a null or
80 * illegal variable name. Legal variable names contain only letters,
81 * numbers, and the underscore character ('_').
83 * @param expression the expression
84 * @param execution the execution
85 * @param fieldName the field name (for logging and exceptions)
86 * @return the output variable name
88 protected String getOutputField(Expression expression,
89 DelegateExecution execution, String fieldName) {
90 Object o = getFieldImpl(expression, execution, fieldName, false);
91 if (o instanceof String) {
92 String variable = (String) o;
93 if (!isLegalVariable(variable)) {
94 throw new BadInjectedFieldException(
95 fieldName, getTaskName(), "'" + variable
96 + "' is not a legal variable name");
100 throw new BadInjectedFieldException(
101 fieldName, getTaskName(), "expected a variable name string"
102 + ", got object of type " + o.getClass().getName());
107 * Get the value of an optional output variable field. This method
108 * throws BadInjectedFieldException if the expression produces an illegal
109 * variable name. Legal variable names contain only letters, numbers,
110 * and the underscore character ('_').
112 * @param expression the expression
113 * @param execution the execution
114 * @param fieldName the field name (for logging and exceptions)
115 * @return the output variable name, possibly null
117 protected String getOptionalOutputField(Expression expression,
118 DelegateExecution execution, String fieldName) {
119 Object o = getFieldImpl(expression, execution, fieldName, true);
120 if (o instanceof String) {
121 String variable = (String) o;
122 if (!isLegalVariable(variable)) {
123 throw new BadInjectedFieldException(
124 fieldName, getTaskName(), "'" + variable
125 + "' is not a legal variable name");
128 } else if (o == null) {
131 throw new BadInjectedFieldException(
132 fieldName, getTaskName(), "expected a variable name string"
133 + ", got object of type " + o.getClass().getName());
138 * Get the value of a required string field. This method throws
139 * MissingInjectedFieldException if the expression is null, and
140 * BadInjectedFieldException if the expression evaluates to a null
143 * Note: the result is coerced to a string value, if necessary.
145 * @param expression the expression
146 * @param execution the execution
147 * @param fieldName the field name (for logging and exceptions)
148 * @return the field value
150 protected String getStringField(Expression expression,
151 DelegateExecution execution, String fieldName) {
152 Object o = getFieldImpl(expression, execution, fieldName, false);
153 if (o instanceof String) {
156 throw new BadInjectedFieldException(
157 fieldName, getTaskName(), "cannot convert '" + o.toString()
163 * Gets the value of an optional string field. There are three conditions
164 * in which this method returns null:
167 * <li> The expression itself is null (i.e. the field is missing
169 * <li>The expression evaluates to a null value.</li>
170 * <li>The expression references a single variable which has not
175 * Expression ${x} when x is null: return null<br>
176 * Expression ${x} when x is unset: return null<br>
177 * Expression ${x+y} when x and/or y are unset: exception<br>
179 * Note: the result is coerced to a string value, if necessary.
181 * @param expression the expression
182 * @param execution the execution
183 * @param fieldName the field name (for logging and exceptions)
184 * @return the field value, possibly null
186 protected String getOptionalStringField(Expression expression,
187 DelegateExecution execution, String fieldName) {
188 Object o = getFieldImpl(expression, execution, fieldName, true);
189 if (o instanceof String) {
191 } else if (o == null) {
199 * Get the value of a required integer field. This method throws
200 * MissingInjectedFieldException if the expression is null, and
201 * BadInjectedFieldException if the expression evaluates to a null
202 * value or a value that cannot be coerced to an integer.
204 * @param expression the expression
205 * @param execution the execution
206 * @param fieldName the field name (for logging and exceptions)
207 * @return the field value
209 protected Integer getIntegerField(Expression expression,
210 DelegateExecution execution, String fieldName) {
211 Object o = getFieldImpl(expression, execution, fieldName, false);
212 if (o instanceof Integer) {
216 return Integer.parseInt(o.toString());
217 } catch (NumberFormatException e) {
218 throw new BadInjectedFieldException(
219 fieldName, getTaskName(), "cannot convert '" + o.toString()
226 * Gets the value of an optional integer field. There are three conditions
227 * in which this method returns null:
230 * <li> The expression itself is null (i.e. the field is missing
232 * <li>The expression evaluates to a null value.</li>
233 * <li>The expression references a single variable which has not
238 * Expression ${x} when x is null: return null<br>
239 * Expression ${x} when x is unset: return null<br>
240 * Expression ${x+y} when x and/or y are unset: exception<br>
242 * Note: the result is coerced to an integer value, if necessary. This
243 * method throws BadInjectedFieldException if the result cannot be coerced
246 * @param expression the expression
247 * @param execution the execution
248 * @param fieldName the field name (for logging and exceptions)
249 * @return the field value, possibly null
251 protected Integer getOptionalIntegerField(Expression expression,
252 DelegateExecution execution, String fieldName) {
253 Object o = getFieldImpl(expression, execution, fieldName, true);
254 if (o instanceof Integer) {
256 } else if (o == null) {
260 return Integer.parseInt(o.toString());
261 } catch (NumberFormatException e) {
262 throw new BadInjectedFieldException(
263 fieldName, getTaskName(), "cannot convert '" + o.toString()
270 * Gets the value of an optional long field. There are three conditions
271 * in which this method returns null:
274 * <li> The expression itself is null (i.e. the field is missing
276 * <li>The expression evaluates to a null value.</li>
277 * <li>The expression references a single variable which has not
282 * Expression ${x} when x is null: return null<br>
283 * Expression ${x} when x is unset: return null<br>
284 * Expression ${x+y} when x and/or y are unset: exception<br>
286 * Note: the result is coerced to a long value, if necessary. This
287 * method throws BadInjectedFieldException if the result cannot be coerced
290 * @param expression the expression
291 * @param execution the execution
292 * @param fieldName the field name (for logging and exceptions)
293 * @return the field value, possibly null
295 protected Long getOptionalLongField(Expression expression,
296 DelegateExecution execution, String fieldName) {
297 Object o = getFieldImpl(expression, execution, fieldName, true);
298 if (o instanceof Long) {
300 } else if (o == null) {
304 return Long.parseLong(o.toString());
305 } catch (NumberFormatException e) {
306 throw new BadInjectedFieldException(
307 fieldName, getTaskName(), "cannot convert '" + o.toString()
314 * Get the value of a required long field. This method throws
315 * MissingInjectedFieldException if the expression is null, and
316 * BadInjectedFieldException if the expression evaluates to a null
317 * value or a value that cannot be coerced to a long.
319 * @param expression the expression
320 * @param execution the execution
321 * @param fieldName the field name (for logging and exceptions)
322 * @return the field value
324 protected Long getLongField(Expression expression,
325 DelegateExecution execution, String fieldName) {
326 Object o = getFieldImpl(expression, execution, fieldName, false);
327 if (o instanceof Long) {
331 return Long.parseLong(o.toString());
332 } catch (NumberFormatException e) {
333 throw new BadInjectedFieldException(
334 fieldName, getTaskName(), "cannot convert '" + o.toString()
341 * Common implementation for field "getter" methods.
343 * @param expression the expression
344 * @param execution the execution
345 * @param fieldName the field name (for logging and exceptions)
346 * @param optional true if the field is optional
347 * @return the field value, possibly null
349 private Object getFieldImpl(Expression expression,
350 DelegateExecution execution, String fieldName, boolean optional) {
351 if (expression == null) {
353 throw new MissingInjectedFieldException(
354 fieldName, getTaskName());
362 value = expression.getValue(execution);
363 } catch (Exception e) {
365 throw new BadInjectedFieldException(
366 fieldName, getTaskName(), e.getClass().getSimpleName(), e);
369 // At this point, we have an exception that occurred while
370 // evaluating an expression for an optional field. A common
371 // problem is that the expression is a simple reference to a
372 // variable which has never been set, e.g. the expression is
373 // ${x}. The normal activiti behavior is to throw an exception,
374 // but we don't like that, so we have the following workaround,
375 // which parses the expression text to see if it is a "simple"
376 // variable reference, and if so, returns null. If the
377 // expression is anything other than a single variable
378 // reference, then an exception is thrown, as it would have
379 // been without this workaround.
381 // Get the expression text so we can parse it
382 String s = expression.getExpressionText();
383 new VariableNameExtractor(s).extract().ifPresent(name -> {
384 if (execution.hasVariable(name)) {
385 throw new BadInjectedFieldException(
386 fieldName, getTaskName(), e.getClass().getSimpleName(), e);
391 if (value == null && !optional) {
392 throw new BadInjectedFieldException(
393 fieldName, getTaskName(), "required field has null value");
400 * Tests if a character is a "word" character.
402 * @param c the character
403 * @return true if the character is a "word" character.
405 private static boolean isWordCharacter(char c) {
406 return (Character.isLetterOrDigit(c) || c == '_');
410 * Tests if the specified string is a legal flow variable name.
412 * @param name the string
413 * @return true if the string is a legal flow variable name
415 private boolean isLegalVariable(String name) {
420 int len = name.length();
426 char c = name.charAt(0);
428 if (!Character.isLetter(c) && c != '_') {
432 for (int i = 1; i < len; i++) {
434 if (!Character.isLetterOrDigit(c) && c != '_') {
443 * Returns the name of the task (normally the java class name).
445 * @return the name of the task
447 public String getTaskName() {
448 return getClass().getSimpleName();
452 public void execute(DelegateExecution execution) throws Exception {