/** * Copyright (C) 2012 BonitaSoft S.A. * BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation * version 2.1 of the License. * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. **/ package org.bonitasoft.forms.server.api.impl; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; import javax.activation.FileTypeMap; import javax.activation.MimetypesFileTypeMap; import org.bonitasoft.console.common.server.utils.BPMEngineAPIUtil; import org.bonitasoft.console.common.server.utils.BPMEngineException; import org.bonitasoft.console.common.server.utils.BPMExpressionEvaluationException; import org.bonitasoft.console.common.server.utils.DocumentUtil; import org.bonitasoft.console.common.server.utils.BonitaHomeFolderAccessor; import org.bonitasoft.engine.api.ProcessAPI; import org.bonitasoft.engine.bpm.document.Document; import org.bonitasoft.engine.bpm.document.DocumentNotFoundException; import org.bonitasoft.engine.bpm.document.DocumentValue; import org.bonitasoft.engine.session.APISession; import org.bonitasoft.engine.session.InvalidSessionException; import org.bonitasoft.forms.client.model.DataFieldDefinition; import org.bonitasoft.forms.client.model.Expression; import org.bonitasoft.forms.client.model.FormFieldValue; import org.bonitasoft.forms.server.accessor.DefaultFormsPropertiesFactory; import org.bonitasoft.forms.server.accessor.api.EngineClientFactory; import org.bonitasoft.forms.server.accessor.api.ExpressionEvaluatorEngineClient; import org.bonitasoft.forms.server.accessor.api.ProcessInstanceAccessorEngineClient; import org.bonitasoft.forms.server.accessor.api.utils.ProcessInstanceAccessor; import org.bonitasoft.forms.server.api.IFormExpressionsAPI; import org.bonitasoft.forms.server.api.impl.util.ExpressionAdapter; import org.bonitasoft.forms.server.exception.FileTooBigException; /** * Implementation of {@link IFormExpressionsAPI} allowing groovy * expressions evaluation and execution * * @author Anthony Birembaut, Zhiheng Yang * */ public class FormExpressionsAPIImpl implements IFormExpressionsAPI { /** * Logger */ private static Logger LOGGER = Logger.getLogger(FormExpressionsAPIImpl.class.getName()); /** * Util class allowing to work with the BPM engine API */ protected BPMEngineAPIUtil bpmEngineAPIUtil = new BPMEngineAPIUtil(); /** * Field id regex */ protected static final String FIELD_REGEX = FIELDID_PREFIX + ".*"; private final EngineClientFactory engineClientFactory = new EngineClientFactory(); /** * evaluate an initial value expression (at form construction) * * @param activityInstanceID * the activity instance ID * @param expression * the expression * @param locale * the user's locale * @param isCurrentValue * if true, value returned is the current value for the instance. otherwise, it's the value at step end * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws BPMEngineException */ @Override public Serializable evaluateActivityInitialExpression(final APISession session, final long activityInstanceID, final Expression expression, final Locale locale, final boolean isCurrentValue) throws InvalidSessionException, BPMExpressionEvaluationException, BPMEngineException { return evaluateActivityInitialExpression(session, activityInstanceID, expression, locale, isCurrentValue, new HashMap<String, Serializable>()); } /** * evaluate an initial value expression (at form construction) * * @param activityInstanceID * the activity instance ID * @param expression * the expression * @param locale * the user's locale * @param isCurrentValue * if true, value returned is the current value for the instance. otherwise, it's the value at step end * @param context * some additional context for groovy evaluation * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws BPMEngineException */ @Override public Serializable evaluateActivityInitialExpression(final APISession session, final long activityInstanceID, final Expression expression, final Locale locale, final boolean isCurrentValue, final Map<String, Serializable> context) throws BPMExpressionEvaluationException, InvalidSessionException, BPMEngineException { Serializable result = null; if (expression != null) { final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); context.put(IFormExpressionsAPI.USER_LOCALE, locale); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); expressionWithContext.put(expressionAdapter.getEngineExpression(expression), context); final ExpressionEvaluatorEngineClient engineClient = getExpressionEvaluator(session); if (isCurrentValue) { final Map<String, Serializable> evaluatedExpressions = engineClient.evaluateExpressionsOnActivityInstance(activityInstanceID, expressionWithContext); result = getFirstResult(evaluatedExpressions); } else { final Map<String, Serializable> evaluatedExpressions = engineClient.evaluateExpressionsOnCompletedActivityInstance(activityInstanceID, expressionWithContext); result = getFirstResult(evaluatedExpressions); } } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } return result; } /** * evaluate an initial value expression (at form construction) * * @param processInstanceID * the process instance ID * @param expression * the expression * @param locale * the user's locale * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException */ @Override public Serializable evaluateInstanceInitialExpression(final APISession session, final long processInstanceID, final Expression expression, final Locale locale, final boolean isCurrentValue) throws BPMEngineException, InvalidSessionException, BPMExpressionEvaluationException { return evaluateInstanceInitialExpression(session, processInstanceID, expression, locale, isCurrentValue, new HashMap<String, Serializable>()); } /** * evaluate an initial value expression (at form construction) * * @param processInstanceId * the process instance ID * @param expression * the expression * @param locale * the user's locale * @param isCurrentValue * if true, value returned is the current value for the instance. otherwise, it's the value at instantiation * @param context * some additional context for groovy evaluation * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException */ @Override public Serializable evaluateInstanceInitialExpression(final APISession session, final long processInstanceId, final Expression expression, final Locale locale, final boolean isCurrentValue, final Map<String, Serializable> context) throws BPMEngineException, InvalidSessionException, BPMExpressionEvaluationException { Serializable result = null; if (expression != null) { final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressions = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); context.put(IFormExpressionsAPI.USER_LOCALE, locale); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); expressions.put(expressionAdapter.getEngineExpression(expression), context); final ProcessInstanceAccessor processInstanceAccessor = getProcessInstanceAccessor(session, processInstanceId); final ProcessInstanceExpressionsEvaluator processInstanceExpressionEvaluator = getProcessInstanceExpressionEvaluator(session); result = getFirstResult(processInstanceExpressionEvaluator.evaluate(processInstanceAccessor, expressions, !isCurrentValue)); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } return result; } protected Serializable getFirstResult(final Map<String, Serializable> evaluatedExpressions) { return evaluatedExpressions.values().iterator().next(); } /** * evaluate an initial value expression (at form construction) * * @param processDefinitionID * the process definition ID * @param expression * the expression * @param locale * the user's locale * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException */ @Override public Serializable evaluateProcessInitialExpression(final APISession session, final long processDefinitionID, final Expression expression, final Locale locale) throws BPMEngineException, InvalidSessionException, BPMExpressionEvaluationException { return evaluateProcessInitialExpression(session, processDefinitionID, expression, locale, new HashMap<String, Serializable>()); } /** * evaluate an initial value expression (at form construction) * * @param processDefinitionID * the process definition ID * @param expression * the expression * @param locale * the user's locale * @param context * some additional context for groovy evaluation * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws BPMEngineException */ @Override public Serializable evaluateProcessInitialExpression(final APISession session, final long processDefinitionID, final Expression expression, final Locale locale, final Map<String, Serializable> context) throws BPMExpressionEvaluationException, InvalidSessionException, BPMEngineException { Serializable result = null; if (expression != null) { context.put(IFormExpressionsAPI.USER_LOCALE, locale); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); expressionWithContext.put(expressionAdapter.getEngineExpression(expression), context); final ExpressionEvaluatorEngineClient engineClient = getExpressionEvaluator(session); result = engineClient.evaluateExpressionsOnProcessDefinition(processDefinitionID, expressionWithContext).values().iterator().next(); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } return result; } /** * Evaluate a field value * * @param session * @param fieldId * the field ID * @param fieldValues * the form field values * @param deleteDocuments * @return the value of the field as an Serializable * @throws FileTooBigException * @throws IOException * @throws InvalidSessionException */ protected Serializable evaluateFieldValueActionExpression(final APISession session, final String fieldId, final Map<String, FormFieldValue> fieldValues, final Locale locale, final boolean deleteDocuments) throws FileTooBigException, IOException, InvalidSessionException, BPMEngineException { Serializable result = null; final FormFieldValue fieldValue = fieldValues.get(fieldId); if (fieldValue != null) { if (fieldValue.isDocument()) { result = getDocumentValue(session, fieldValue, deleteDocuments); } else { result = fieldValue.getValue(); } } return result; } /** * Get the content of the document * * @param session * @param fieldValue * @param deleteDocument * @return the document value * @throws FileTooBigException * @throws IOException * @throws InvalidSessionException */ protected DocumentValue getDocumentValue(final APISession session, final FormFieldValue fieldValue, final boolean deleteDocument) throws FileTooBigException, IOException, InvalidSessionException, BPMEngineException { DocumentValue documentValue = null; final String uri = (String) fieldValue.getValue(); if (File.class.getName().equals(fieldValue.getValueType())) { // File widget is selected documentValue = getFileDocumentValue(session, fieldValue, deleteDocument, uri); } else { // Url type file widget is selected documentValue = getURLDocumentValue(session, fieldValue, uri); } //set the document ID if the widget was already displaying a document value if (documentValue != null && fieldValue.getDocumentId() != -1) { documentValue.setDocumentId(fieldValue.getDocumentId()); } return documentValue; } protected DocumentValue getURLDocumentValue(final APISession session, final FormFieldValue fieldValue, final String uri) throws BPMEngineException { DocumentValue documentValue = null; final Document document = getCurrentDocumentValue(session, fieldValue); if (document != null) { if (uri == null && document.getUrl() != null || uri != null && !uri.equals(document.getUrl())) { // the url has changed or the document was a file type documentValue = new DocumentValue(uri); documentValue.setHasChanged(true); } else { // file widget content has not changed documentValue = new DocumentValue(null); documentValue.setHasChanged(false); } } else { documentValue = new DocumentValue(uri); documentValue.setHasChanged(true); } return documentValue; } protected Document getCurrentDocumentValue(final APISession session, final FormFieldValue fieldValue) throws BPMEngineException { Document document = null; if (fieldValue.getDocumentId() != -1) { // A document was displayed in the widget final ProcessAPI processAPI = bpmEngineAPIUtil.getProcessAPI(session); try { document = processAPI.getDocument(fieldValue.getDocumentId()); } catch (final DocumentNotFoundException e) { if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.log(Level.SEVERE, "Error while retrieving the document with ID " + fieldValue.getDocumentId() + ": Document not found."); } } } return document; } protected DocumentValue getFileDocumentValue(final APISession session, final FormFieldValue fieldValue, final boolean deleteDocument, final String uri) throws FileTooBigException, IOException { DocumentValue documentValue = null; if (uri != null && uri.length() != 0) { // A new file widget content has been set documentValue = getNewFileDocumentValue(session, fieldValue, deleteDocument, uri); } else if (fieldValue.getDocumentId() != -1 && fieldValue.getDisplayedValue() != null) { // file widget content has not changed documentValue = new DocumentValue(null); documentValue.setHasChanged(false); } return documentValue; } protected BonitaHomeFolderAccessor getTenantFolder() { return new BonitaHomeFolderAccessor(); } protected DocumentValue getNewFileDocumentValue(final APISession session, final FormFieldValue fieldValue, final boolean deleteDocument, final String uri) throws FileTooBigException, IOException { DocumentValue documentValue = null; final File theSourceFile = getTenantFolder().getTempFile(uri, session.getTenantId()); if (theSourceFile.exists()) { final long maxSize = getDocumentMaxSize(session); if (theSourceFile.length() > maxSize * 1048576) { final String errorMessage = "file " + uri + " too big !"; if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.log(Level.SEVERE, errorMessage); } throw new FileTooBigException(errorMessage, uri, String.valueOf(maxSize)); } final byte[] fileContent = DocumentUtil.getArrayByteFromFile(theSourceFile); final String originalFileName = fieldValue.getDisplayedValue(); final FileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap(); final String contentType = mimetypesFileTypeMap.getContentType(theSourceFile); documentValue = new DocumentValue(fileContent, contentType, originalFileName); documentValue.setHasChanged(true); if (deleteDocument) { theSourceFile.delete(); } } else { if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.log(Level.SEVERE, "Error while retrieving the uploaded file " + uri + ": File not found."); } } return documentValue; } protected long getDocumentMaxSize(final APISession session) { return DefaultFormsPropertiesFactory.getDefaultFormProperties(session.getTenantId()).getAttachmentMaxSize(); } /** * Generate the form fields context for a groovy evaluation * * @param session * @param fieldValues * @param locale * @param deleteDocuments * @return the context * @throws IOException * @throws FileTooBigException * @throws InvalidSessionException */ @Override public Map<String, Serializable> generateGroovyContext(final APISession session, final Map<String, FormFieldValue> fieldValues, final Locale locale, Map<String, Serializable> context, final boolean deleteDocuments) throws FileTooBigException, IOException, InvalidSessionException, BPMEngineException { if (context == null) { context = new HashMap<String, Serializable>(); } for (final Entry<String, FormFieldValue> fieldValuesEntry : fieldValues.entrySet()) { final String fieldId = fieldValuesEntry.getKey(); final Serializable fieldValue = evaluateFieldValueActionExpression(session, fieldId, fieldValues, locale, deleteDocuments); context.put(FIELDID_PREFIX + fieldId, fieldValue); } context.put(IFormExpressionsAPI.USER_LOCALE, locale); return context; } /** * Evaluate an expression (at form submission) * * @param activityInstanceID * the activity instance ID * @param expression * the expression * @param fieldValues * the form field values * @param locale * the user's locale * @param isCurrentValue * if true, value returned is the current value for the instance. otherwise, it's the value at step end * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException * @throws BPMEngineException */ @Override public Serializable evaluateActivityExpression(final APISession session, final long activityInstanceID, final Expression expression, final Map<String, FormFieldValue> fieldValues, final Locale locale, final boolean isCurrentValue) throws BPMExpressionEvaluationException, InvalidSessionException, FileTooBigException, IOException, BPMEngineException { return evaluateActivityExpression(session, activityInstanceID, expression, fieldValues, locale, isCurrentValue, null); } /** * Evaluate an expression (at form submission) * * @param activityInstanceID * the activity instance ID * @param expression * the expression * @param fieldValues * the form field values * @param locale * the user's locale * @param isCurrentValue * if true, value returned is the current value for the instance. otherwise, it's the value at instantiation * @param context * some additional context for groovy evaluation * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException * @throws BPMEngineException */ @Override public Serializable evaluateActivityExpression(final APISession session, final long activityInstanceID, final Expression expression, final Map<String, FormFieldValue> fieldValues, final Locale locale, final boolean isCurrentValue, final Map<String, Serializable> context) throws BPMExpressionEvaluationException, InvalidSessionException, FileTooBigException, IOException, BPMEngineException { Serializable result = null; if (expression != null) { final Map<String, Serializable> evalContext = generateGroovyContext(session, fieldValues, locale, context, false); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); expressionWithContext.put(expressionAdapter.getEngineExpression(expression), evalContext); final ExpressionEvaluatorEngineClient engineClient = getExpressionEvaluator(session); if (isCurrentValue) { final Map<String, Serializable> evaluatedExpressions = engineClient.evaluateExpressionsOnActivityInstance(activityInstanceID, expressionWithContext); result = getFirstResult(evaluatedExpressions); } else { final Map<String, Serializable> evaluatedExpressions = engineClient.evaluateExpressionsOnCompletedActivityInstance(activityInstanceID, expressionWithContext); result = getFirstResult(evaluatedExpressions); } } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } return result; } /** * Evaluate an expression (at form submission) * * @param processInstanceID * the process instance ID * @param expression * the expression * @param fieldValues * the form field values * @param locale * the user's locale * @param isCurrentValue * if true, value returned is the current value for the instance. otherwise, it's the value at instantiation * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException */ @Override public Serializable evaluateInstanceExpression(final APISession session, final long processInstanceID, final Expression expression, final Map<String, FormFieldValue> fieldValues, final Locale locale, final boolean isCurrentValue) throws BPMEngineException, InvalidSessionException, FileTooBigException, IOException, BPMExpressionEvaluationException { return evaluateInstanceExpression(session, processInstanceID, expression, fieldValues, locale, isCurrentValue, null); } /** * Evaluate an expression (at form submission) * * @param processInstanceId * the process instance ID * @param expression * the expression * @param fieldValues * the form field values * @param locale * the user's locale * @param isCurrentValue * if true, value returned is the current value for the instance. otherwise, it's the value at instantiation * @param context * some additional context for groovy evaluation * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException */ @Override public Serializable evaluateInstanceExpression(final APISession session, final long processInstanceId, final Expression expression, final Map<String, FormFieldValue> fieldValues, final Locale locale, final boolean isCurrentValue, final Map<String, Serializable> context) throws BPMEngineException, InvalidSessionException, FileTooBigException, IOException, BPMExpressionEvaluationException { Serializable result = null; if (expression != null) { final Map<String, Serializable> evalContext = generateGroovyContext(session, fieldValues, locale, context, false); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressions = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); expressions.put(expressionAdapter.getEngineExpression(expression), evalContext); result = getFirstResult(getProcessInstanceExpressionEvaluator(session).evaluate(getProcessInstanceAccessor(session, processInstanceId), expressions, !isCurrentValue)); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } return result; } /** * Evaluate an action expression (at form submission) * * @param processDefinitionID * the process definition ID * @param expression * the expression * @param fieldValues * the form field values * @param locale * the user's locale * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException * @throws BPMEngineException */ @Override public Serializable evaluateProcessExpression(final APISession session, final long processDefinitionID, final Expression expression, final Map<String, FormFieldValue> fieldValues, final Locale locale) throws BPMExpressionEvaluationException, InvalidSessionException, FileTooBigException, IOException, BPMEngineException { return evaluateProcessExpression(session, processDefinitionID, expression, fieldValues, locale, null); } /** * Evaluate an action expression (at form submission) * * @param processDefinitionID * the process definition ID * @param expression * the expression * @param fieldValues * the form field values * @param locale * the user's locale * @param context * some additional context for groovy evaluation * @return The result of the evaluation * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException * @throws BPMEngineException */ @Override public Serializable evaluateProcessExpression(final APISession session, final long processDefinitionID, final Expression expression, final Map<String, FormFieldValue> fieldValues, final Locale locale, final Map<String, Serializable> context) throws BPMExpressionEvaluationException, InvalidSessionException, FileTooBigException, IOException, BPMEngineException { Serializable result = null; if (expression != null) { final Map<String, Serializable> evalContext = generateGroovyContext(session, fieldValues, locale, context, false); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); expressionWithContext.put(expressionAdapter.getEngineExpression(expression), evalContext); final ExpressionEvaluatorEngineClient engineClient = getExpressionEvaluator(session); final Map<String, Serializable> evaluatedExpressions = engineClient.evaluateExpressionsOnProcessDefinition(processDefinitionID, expressionWithContext); result = getFirstResult(evaluatedExpressions); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } return result; } /** * Get the right object value according to the datafield definition * * @param value * the value as extracted from the {@link FormFieldValue} object * @param dataTypeClassName * the datafield classname * @return The object matching the {@link DataFieldDefinition} */ @Override public Serializable getSerializableValue(final Serializable value, final String dataTypeClassName) { Serializable objectValue = null; if (value != null) { if (!String.class.getName().equals(dataTypeClassName) && value instanceof String && value.toString().length() == 0) { objectValue = null; } else if (Boolean.class.getName().equals(dataTypeClassName)) { objectValue = Boolean.parseBoolean(value.toString()); } else if (Integer.class.getName().equals(dataTypeClassName)) { objectValue = Integer.parseInt(value.toString()); } else if (Long.class.getName().equals(dataTypeClassName)) { objectValue = Long.parseLong(value.toString()); } else if (Float.class.getName().equals(dataTypeClassName)) { objectValue = Float.parseFloat(value.toString()); } else if (Double.class.getName().equals(dataTypeClassName)) { objectValue = Double.parseDouble(value.toString()); } else if (Short.class.getName().equals(dataTypeClassName)) { objectValue = Short.parseShort(value.toString()); } else if (Character.class.getName().equals(dataTypeClassName)) { objectValue = value.toString().charAt(0); } else { objectValue = value; } } return objectValue; } /** * evaluate an initial value expression (at form construction) * * @param activityInstanceID * the activity instance ID * @param expressions * the map of expressions to evaluate * @param locale * the user's locale * @param isCurrentValue * if true, values returned are the current values for the instance. otherwise, it's the values at step end * @param context * some additional context for groovy evaluation * @return The result of the evaluations as a Map * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws BPMEngineException */ @Override public Map<String, Serializable> evaluateActivityInitialExpressions(final APISession session, final long activityInstanceID, final List<Expression> expressions, final Locale locale, final boolean isCurrentValue, final Map<String, Serializable> context) throws BPMExpressionEvaluationException, InvalidSessionException, BPMEngineException { final Map<String, Serializable> result = new HashMap<String, Serializable>(); context.put(IFormExpressionsAPI.USER_LOCALE, locale); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionsWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); for (final Expression expression : expressions) { if (expression != null) { expressionsWithContext.put(expressionAdapter.getEngineExpression(expression), context); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } } if (!expressionsWithContext.isEmpty()) { Map<String, Serializable> evaluated; final ExpressionEvaluatorEngineClient engineClient = getExpressionEvaluator(session); if (isCurrentValue) { evaluated = engineClient.evaluateExpressionsOnActivityInstance(activityInstanceID, expressionsWithContext); } else { evaluated = engineClient.evaluateExpressionsOnCompletedActivityInstance(activityInstanceID, expressionsWithContext); } result.putAll(evaluated); } return result; } /** * Evaluate an expression (at form submission) * * @param activityInstanceID * the activity instance ID * @param expressions * the map of expressions to evaluate * @param fieldValues * the form field values * @param locale * the user's locale * @param isCurrentValue * if true, values returned are the current values for the instance. otherwise, it's the values at step end * @param context * some additional context for groovy evaluation * @return The result of the evaluations as a Map * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException * @throws BPMEngineException */ @Override public Map<String, Serializable> evaluateActivityExpressions(final APISession session, final long activityInstanceID, final List<Expression> expressions, final Map<String, FormFieldValue> fieldValues, final Locale locale, final boolean isCurrentValue, Map<String, Serializable> context) throws BPMExpressionEvaluationException, InvalidSessionException, FileTooBigException, IOException, BPMEngineException { final Map<String, Serializable> result = new HashMap<String, Serializable>(); context.put(IFormExpressionsAPI.USER_LOCALE, locale); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionsWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); for (final Expression expression : expressions) { if (expression != null) { expressionsWithContext.put(expressionAdapter.getEngineExpression(expression), context); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } } if (!expressionsWithContext.isEmpty()) { context = generateGroovyContext(session, fieldValues, locale, context, false); Map<String, Serializable> evaluated; final ExpressionEvaluatorEngineClient engineClient = getExpressionEvaluator(session); if (isCurrentValue) { evaluated = engineClient.evaluateExpressionsOnActivityInstance(activityInstanceID, expressionsWithContext); } else { evaluated = engineClient.evaluateExpressionsOnCompletedActivityInstance(activityInstanceID, expressionsWithContext); } result.putAll(evaluated); } return result; } /** * Evaluate an expression (at form construction) * * @param processInstanceId * the process instance ID * @param expressions * the map of expressions to evaluate * @param locale * the user's locale * @param isCurrentValue * if true, values returned are the current values for the instance. otherwise, it's the values at process instantiation * @param context * some additional context for groovy evaluation * @return The result of the evaluations as a Map * @throws BPMExpressionEvaluationException * , InvalidSessionException */ @Override public Map<String, Serializable> evaluateInstanceInitialExpressions(final APISession session, final long processInstanceId, final List<Expression> expressions, final Locale locale, final boolean isCurrentValue, final Map<String, Serializable> context) throws BPMEngineException, InvalidSessionException, BPMExpressionEvaluationException { final Map<String, Serializable> result = new HashMap<String, Serializable>(); context.put(IFormExpressionsAPI.USER_LOCALE, locale); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionsWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); for (final Expression expression : expressions) { if (expression != null) { expressionsWithContext.put(expressionAdapter.getEngineExpression(expression), context); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } } if (!expressionsWithContext.isEmpty()) { result.putAll(getProcessInstanceExpressionEvaluator(session).evaluate(getProcessInstanceAccessor(session, processInstanceId), expressionsWithContext, !isCurrentValue)); } return result; } protected ProcessInstanceAccessor getProcessInstanceAccessor(final APISession session, final long processInstanceId) throws BPMEngineException { return new ProcessInstanceAccessor(getEngineProcessInstanceAccessor(session), processInstanceId); } protected ProcessInstanceExpressionsEvaluator getProcessInstanceExpressionEvaluator(final APISession session) throws BPMEngineException { return new ProcessInstanceExpressionsEvaluator(getExpressionEvaluator(session)); } private ExpressionEvaluatorEngineClient getExpressionEvaluator(final APISession session) throws BPMEngineException { return engineClientFactory.createExpressionEvaluatorEngineClient(session); } private ProcessInstanceAccessorEngineClient getEngineProcessInstanceAccessor(final APISession session) throws BPMEngineException { return engineClientFactory.createProcessInstanceEngineClient(session); } /** * Evaluate an expression (at form submission) * * @param processInstanceId * the process instance ID * @param expressions * the map of expressions to evaluate * @param fieldValues * the form field values * @param locale * the user's locale * @param isCurrentValue * if true, values returned are the current values for the instance. otherwise, it's the values at process instantiation * @param context * some additional context for groovy evaluation * @return The result of the evaluations as a Map * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException */ @Override public Map<String, Serializable> evaluateInstanceExpressions(final APISession session, final long processInstanceId, final List<Expression> expressions, final Map<String, FormFieldValue> fieldValues, final Locale locale, final boolean isCurrentValue, Map<String, Serializable> context) throws BPMEngineException, InvalidSessionException, FileTooBigException, IOException, BPMExpressionEvaluationException { final Map<String, Serializable> result = new HashMap<String, Serializable>(); context.put(IFormExpressionsAPI.USER_LOCALE, locale); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionsWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); for (final Expression expression : expressions) { if (expression != null) { expressionsWithContext.put(expressionAdapter.getEngineExpression(expression), context); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } } if (!expressionsWithContext.isEmpty()) { context = generateGroovyContext(session, fieldValues, locale, context, false); result.putAll(getProcessInstanceExpressionEvaluator(session).evaluate(getProcessInstanceAccessor(session, processInstanceId), expressionsWithContext, !isCurrentValue)); } return result; } /** * Evaluate an expression (at form construction) * * @param processDefinitionID * the process definition ID * @param expressions * the map of expressions to evaluate * @param locale * the user's locale * @param context * some additional context for groovy evaluation * @return The result of the evaluations as a Map * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws BPMEngineException */ @Override public Map<String, Serializable> evaluateProcessInitialExpressions(final APISession session, final long processDefinitionID, final List<Expression> expressions, final Locale locale, final Map<String, Serializable> context) throws BPMExpressionEvaluationException, InvalidSessionException, BPMEngineException { final Map<String, Serializable> result = new HashMap<String, Serializable>(); context.put(IFormExpressionsAPI.USER_LOCALE, locale); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionsWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); for (final Expression expression : expressions) { if (expression != null) { expressionsWithContext.put(expressionAdapter.getEngineExpression(expression), context); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } } if (!expressionsWithContext.isEmpty()) { final ExpressionEvaluatorEngineClient engineClient = getExpressionEvaluator(session); result.putAll(engineClient.evaluateExpressionsOnProcessDefinition(processDefinitionID, expressionsWithContext)); } return result; } /** * Evaluate an expression (at form submission) * * @param processDefinitionID * the process definition ID * @param expressions * the map of expressions to evaluate * @param fieldValues * the form field values * @param locale * the user's locale * @param context * some additional context for groovy evaluation * @return The result of the evaluations as a Map * @throws BPMExpressionEvaluationException * , InvalidSessionException * @throws IOException * @throws FileTooBigException * @throws BPMEngineException */ @Override public Map<String, Serializable> evaluateProcessExpressions(final APISession session, final long processDefinitionID, final List<Expression> expressions, final Map<String, FormFieldValue> fieldValues, final Locale locale, Map<String, Serializable> context) throws BPMExpressionEvaluationException, InvalidSessionException, FileTooBigException, IOException, BPMEngineException { final Map<String, Serializable> result = new HashMap<String, Serializable>(); context.put(IFormExpressionsAPI.USER_LOCALE, locale); final Map<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>> expressionsWithContext = new HashMap<org.bonitasoft.engine.expression.Expression, Map<String, Serializable>>(); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(); for (final Expression expression : expressions) { if (expression != null) { expressionsWithContext.put(expressionAdapter.getEngineExpression(expression), context); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "The expression or its type are null"); } } } if (!expressionsWithContext.isEmpty()) { context = generateGroovyContext(session, fieldValues, locale, context, false); result.putAll(getExpressionEvaluator(session).evaluateExpressionsOnProcessDefinition(processDefinitionID, expressionsWithContext)); } return result; } }