/*- * ============LICENSE_START======================================================= * OPENECOMP - MSO * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ package org.openecomp.mso.bpmn.core; import java.util.Objects; import org.camunda.bpm.engine.ProcessEngineException; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.Expression; import org.camunda.bpm.engine.delegate.JavaDelegate; /** * Base class for service tasks. */ public abstract class BaseTask implements JavaDelegate { /** * Get the value of a required field. This method throws * MissingInjectedFieldException if the expression is null, and * BadInjectedFieldException if the expression evaluates to a null * value. * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the field value */ protected Object getField(Expression expression, DelegateExecution execution, String fieldName) { return getFieldImpl(expression, execution, fieldName, false); } /** * Gets the value of an optional field. There are three conditions * in which this method returns null: *

*

    *
  1. The expression itself is null (i.e. the field is missing * altogether.
  2. *
  3. The expression evaluates to a null value.
  4. *
  5. The expression references a single variable which has not * been set.
  6. *
*

* Examples:
* Expression ${x} when x is null: return null
* Expression ${x} when x is unset: return null
* Expression ${x+y} when x and/or y are unset: exception
* * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the field value, possibly null */ protected Object getOptionalField(Expression expression, DelegateExecution execution, String fieldName) { return getFieldImpl(expression, execution, fieldName, true); } /** * Get the value of a required output variable field. This method * throws MissingInjectedFieldException if the expression is null, and * BadInjectedFieldException if the expression produces a null or * illegal variable name. Legal variable names contain only letters, * numbers, and the underscore character ('_'). * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the output variable name */ protected String getOutputField(Expression expression, DelegateExecution execution, String fieldName) { Object o = getFieldImpl(expression, execution, fieldName, false); if (o instanceof String) { String variable = (String) o; if (!isLegalVariable(variable)) { throw new BadInjectedFieldException( fieldName, getTaskName(), "'" + variable + "' is not a legal variable name"); } return variable; } else { throw new BadInjectedFieldException( fieldName, getTaskName(), "expected a variable name string" + ", got object of type " + o.getClass().getName()); } } /** * Get the value of an optional output variable field. This method * throws BadInjectedFieldException if the expression produces an illegal * variable name. Legal variable names contain only letters, numbers, * and the underscore character ('_'). * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the output variable name, possibly null */ protected String getOptionalOutputField(Expression expression, DelegateExecution execution, String fieldName) { Object o = getFieldImpl(expression, execution, fieldName, true); if (o instanceof String) { String variable = (String) o; if (!isLegalVariable(variable)) { throw new BadInjectedFieldException( fieldName, getTaskName(), "'" + variable + "' is not a legal variable name"); } return variable; } else if (o == null) { return null; } else { throw new BadInjectedFieldException( fieldName, getTaskName(), "expected a variable name string" + ", got object of type " + o.getClass().getName()); } } /** * Get the value of a required string field. This method throws * MissingInjectedFieldException if the expression is null, and * BadInjectedFieldException if the expression evaluates to a null * value. *

* Note: the result is coerced to a string value, if necessary. * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the field value */ protected String getStringField(Expression expression, DelegateExecution execution, String fieldName) { Object o = getFieldImpl(expression, execution, fieldName, false); if (o instanceof String) { return (String) o; } else { throw new BadInjectedFieldException( fieldName, getTaskName(), "cannot convert '" + o.toString() + "' to Integer"); } } /** * Gets the value of an optional string field. There are three conditions * in which this method returns null: *

*

    *
  1. The expression itself is null (i.e. the field is missing * altogether.
  2. *
  3. The expression evaluates to a null value.
  4. *
  5. The expression references a single variable which has not * been set.
  6. *
*

* Examples:
* Expression ${x} when x is null: return null
* Expression ${x} when x is unset: return null
* Expression ${x+y} when x and/or y are unset: exception
*

* Note: the result is coerced to a string value, if necessary. * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the field value, possibly null */ protected String getOptionalStringField(Expression expression, DelegateExecution execution, String fieldName) { Object o = getFieldImpl(expression, execution, fieldName, true); return Objects.toString(o, null); } /** * Get the value of a required integer field. This method throws * MissingInjectedFieldException if the expression is null, and * BadInjectedFieldException if the expression evaluates to a null * value or a value that cannot be coerced to an integer. * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the field value */ protected Integer getIntegerField(Expression expression, DelegateExecution execution, String fieldName) { Object o = getFieldImpl(expression, execution, fieldName, false); if (o instanceof Integer) { return (Integer) o; } else { try { return Integer.parseInt(o.toString()); } catch (NumberFormatException e) { throw new BadInjectedFieldException( fieldName, getTaskName(), "cannot convert '" + o.toString() + "' to Integer"); } } } /** * Gets the value of an optional integer field. There are three conditions * in which this method returns null: *

*

    *
  1. The expression itself is null (i.e. the field is missing * altogether.
  2. *
  3. The expression evaluates to a null value.
  4. *
  5. The expression references a single variable which has not * been set.
  6. *
*

* Examples:
* Expression ${x} when x is null: return null
* Expression ${x} when x is unset: return null
* Expression ${x+y} when x and/or y are unset: exception
*

* Note: the result is coerced to an integer value, if necessary. This * method throws BadInjectedFieldException if the result cannot be coerced * to an integer. * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the field value, possibly null */ protected Integer getOptionalIntegerField(Expression expression, DelegateExecution execution, String fieldName) { Object o = getFieldImpl(expression, execution, fieldName, true); if (o instanceof Integer) { return (Integer) o; } else if (o == null) { return null; } else { try { return Integer.parseInt(o.toString()); } catch (NumberFormatException e) { throw new BadInjectedFieldException( fieldName, getTaskName(), "cannot convert '" + o.toString() + "' to Integer"); } } } /** * Gets the value of an optional long field. There are three conditions * in which this method returns null: *

*

    *
  1. The expression itself is null (i.e. the field is missing * altogether.
  2. *
  3. The expression evaluates to a null value.
  4. *
  5. The expression references a single variable which has not * been set.
  6. *
*

* Examples:
* Expression ${x} when x is null: return null
* Expression ${x} when x is unset: return null
* Expression ${x+y} when x and/or y are unset: exception
*

* Note: the result is coerced to a long value, if necessary. This * method throws BadInjectedFieldException if the result cannot be coerced * to a long. * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the field value, possibly null */ protected Long getOptionalLongField(Expression expression, DelegateExecution execution, String fieldName) { Object o = getFieldImpl(expression, execution, fieldName, true); if (o instanceof Long) { return (Long) o; } else if (o == null) { return null; } else { try { return Long.parseLong(o.toString()); } catch (NumberFormatException e) { throw new BadInjectedFieldException( fieldName, getTaskName(), "cannot convert '" + o.toString() + "' to Long"); } } } /** * Get the value of a required long field. This method throws * MissingInjectedFieldException if the expression is null, and * BadInjectedFieldException if the expression evaluates to a null * value or a value that cannot be coerced to a long. * * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @return the field value */ protected Long getLongField(Expression expression, DelegateExecution execution, String fieldName) { Object o = getFieldImpl(expression, execution, fieldName, false); if (o instanceof Long) { return (Long) o; } else { try { return Long.parseLong(o.toString()); } catch (NumberFormatException e) { throw new BadInjectedFieldException( fieldName, getTaskName(), "cannot convert '" + o.toString() + "' to Long"); } } } /** * Common implementation for field "getter" methods. * @param expression the expression * @param execution the execution * @param fieldName the field name (for logging and exceptions) * @param optional true if the field is optional * @return the field value, possibly null */ private Object getFieldImpl(Expression expression, DelegateExecution execution, String fieldName, boolean optional) { if (expression == null) { if (!optional) { throw new MissingInjectedFieldException( fieldName, getTaskName()); } return null; } Object value; try { value = expression.getValue(execution); } catch (Exception e) { if (!optional) { throw new BadInjectedFieldException( fieldName, getTaskName(), e.getClass().getSimpleName(), e); } // At this point, we have an exception that occurred while // evaluating an expression for an optional field. A common // problem is that the expression is a simple reference to a // variable which has never been set, e.g. the expression is // ${x}. The normal activiti behavior is to throw an exception, // but we don't like that, so we have the following workaround, // which parses the expression text to see if it is a "simple" // variable reference, and if so, returns null. If the // expression is anything other than a single variable // reference, then an exception is thrown, as it would have // been without this workaround. // Get the expression text so we can parse it String s = expression.getExpressionText(); // if (isDebugEnabled(execution)) { // logDebug(execution, getTaskName() + " field '" + fieldName // + "' expression evaluation failed: " + s); // } int len = s.length(); int i = 0; // Skip whitespace while (i < len && Character.isWhitespace(s.charAt(i))) { i++; } // Next character must be '$' if (i == len || s.charAt(i++) != '$') { throw new BadInjectedFieldException( fieldName, getTaskName(), e.getClass().getSimpleName(), e); } // Skip whitespace while (i < len && Character.isWhitespace(s.charAt(i))) { i++; } // Next character must be '{' if (i == len || s.charAt(i++) != '{') { throw new BadInjectedFieldException( fieldName, getTaskName(), e.getClass().getSimpleName(), e); } // Skip whitespace while (i < len && Character.isWhitespace(s.charAt(i))) { i++; } // Collect the variable name StringBuilder variable = new StringBuilder(); while (i < len && isWordCharacter(s.charAt(i))) { variable.append(s.charAt(i)); i++; } if (variable.length() == 0) { throw new BadInjectedFieldException( fieldName, getTaskName(), e.getClass().getSimpleName(), e); } // Skip whitespace while (i < len && Character.isWhitespace(s.charAt(i))) { i++; } // Next character must be '}' if (i == len || s.charAt(i++) != '}') { throw new BadInjectedFieldException( fieldName, getTaskName(), e.getClass().getSimpleName(), e); } // Skip whitespace while (i < len && Character.isWhitespace(s.charAt(i))) { i++; } // Must be at end of string if (i != len) { throw new BadInjectedFieldException( fieldName, getTaskName(), e.getClass().getSimpleName(), e); } // if (isDebugEnabled(execution)) { // logDebug(execution, "Checking if variable '" // + variable.toString() + "' exists"); // } // If the variable exists then the problem was // something else... if (execution.hasVariable(variable.toString())) { throw new BadInjectedFieldException( fieldName, getTaskName(), e.getClass().getSimpleName(), e); } // The variable doesn't exist. // if (isDebugEnabled(execution)) { // logDebug(execution, "Variable '" + variable.toString() // + "' does not exist [ok]"); // } value = null; } if (value == null && !optional) { throw new BadInjectedFieldException( fieldName, getTaskName(), "required field has null value"); } return value; } /** * Tests if a character is a "word" character. * @param c the character * @return true if the character is a "word" character. */ private boolean isWordCharacter(char c) { return (Character.isLetterOrDigit(c) || c == '_'); } /** * Tests if the specified string is a legal flow variable name. * @param name the string * @return true if the string is a legal flow variable name */ private boolean isLegalVariable(String name) { if (name == null) { return false; } int len = name.length(); if (len == 0) { return false; } char c = name.charAt(0); if (!Character.isLetter(c) && c != '_') { return false; } for (int i = 1; i < len; i++) { c = name.charAt(i); if (!Character.isLetterOrDigit(c) && c != '_') { return false; } } return true; } /** * Returns the name of the task (normally the java class name). * @return the name of the task */ public String getTaskName() { return getClass().getSimpleName(); } /** * Check if shouldFail variable is set to true. * @param execution * @return */ protected boolean shouldFail(DelegateExecution execution) { Boolean shouldFail = (Boolean) execution.getVariable("shouldFail"); return shouldFail != null && shouldFail; } }