Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ow2.bonita.util.ProcessBuilder Maven / Gradle / Ivy
/**
* Copyright (C) 2009-2013 BonitaSoft S.A.
* BonitaSoft, 31 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.ow2.bonita.util;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import org.ow2.bonita.building.XmlDefExporter;
import org.ow2.bonita.connector.core.Connector;
import org.ow2.bonita.connector.core.RoleResolver;
import org.ow2.bonita.facade.def.element.AttachmentDefinition;
import org.ow2.bonita.facade.def.element.BoundaryEvent;
import org.ow2.bonita.facade.def.element.FilterDefinition;
import org.ow2.bonita.facade.def.element.HookDefinition.Event;
import org.ow2.bonita.facade.def.element.IncomingEventDefinition;
import org.ow2.bonita.facade.def.element.MultiInstantiationDefinition;
import org.ow2.bonita.facade.def.element.RoleMapperDefinition;
import org.ow2.bonita.facade.def.element.impl.AttachmentDefinitionImpl;
import org.ow2.bonita.facade.def.element.impl.ConnectorDefinitionImpl;
import org.ow2.bonita.facade.def.element.impl.ErrorBoundaryEventImpl;
import org.ow2.bonita.facade.def.element.impl.EventDefinitionImpl;
import org.ow2.bonita.facade.def.element.impl.IncomingEventDefinitionImpl;
import org.ow2.bonita.facade.def.element.impl.MessageBoundaryEventImpl;
import org.ow2.bonita.facade.def.element.impl.OutgoingEventDefinitionImpl;
import org.ow2.bonita.facade.def.element.impl.SignalBoundaryEventImpl;
import org.ow2.bonita.facade.def.element.impl.SubflowParameterDefinitionImpl;
import org.ow2.bonita.facade.def.element.impl.TimerBoundaryEventImpl;
import org.ow2.bonita.facade.def.majorElement.ActivityDefinition;
import org.ow2.bonita.facade.def.majorElement.ActivityDefinition.JoinType;
import org.ow2.bonita.facade.def.majorElement.ActivityDefinition.SplitType;
import org.ow2.bonita.facade.def.majorElement.DataFieldDefinition;
import org.ow2.bonita.facade.def.majorElement.ParticipantDefinition;
import org.ow2.bonita.facade.def.majorElement.ProcessDefinition;
import org.ow2.bonita.facade.def.majorElement.TransitionDefinition;
import org.ow2.bonita.facade.def.majorElement.impl.ActivityDefinitionImpl;
import org.ow2.bonita.facade.def.majorElement.impl.DataFieldDefinitionImpl;
import org.ow2.bonita.facade.def.majorElement.impl.DescriptionElementImpl;
import org.ow2.bonita.facade.def.majorElement.impl.EventProcessDefinitionImpl;
import org.ow2.bonita.facade.def.majorElement.impl.NamedElementImpl;
import org.ow2.bonita.facade.def.majorElement.impl.ParticipantDefinitionImpl;
import org.ow2.bonita.facade.def.majorElement.impl.ProcessDefinitionImpl;
import org.ow2.bonita.facade.def.majorElement.impl.TransitionDefinitionImpl;
import org.ow2.bonita.light.LightProcessDefinition.ProcessType;
import org.ow2.bonita.parsing.def.XmlDefParser;
import org.ow2.bonita.parsing.xpdl.XpdlParser;
import org.ow2.bonita.util.xml.Parse;
import org.ow2.bonita.util.xml.Problem;
import org.w3c.dom.Document;
/**
* A ProcessBuilder constructs a process by adding methods.
*
* @author Matthieu Chaffotte, Charles Souillard, Elias Ricken de Medeiros
*
*/
public final class ProcessBuilder {
private final Collection problems;
private final Stack stack;
private OutgoingEventDefinitionImpl outgoingEvent;
/**
* Creates a process definition with a unique name and a process version. In
* order to get this process definition the done method should be called at
* the end of the process build.
*
* @param name
* the process name
* @param version
* the process version
* @return the ProcessBuilder in order to add BPM elements
*/
public static ProcessBuilder createProcess(final String name, final String version) {
return new ProcessBuilder(name, version);
}
/**
* Creates a process definition using an XPDL file.
*
* @param xpdlUrl
* the URL of the XPDL file
* @return a process definition
*/
public static ProcessDefinition createProcessFromXpdlFile(final URL xpdlUrl) {
final Parse parse = new XpdlParser().createParse();
parse.setUrl(xpdlUrl);
final ProcessDefinition process = (ProcessDefinition) parse.execute().getDocumentObject();
Misc.showProblems(parse.getProblems(), "xpdl file");
Misc.badStateIfNull(process, "Ouch! The returned client process is null!");
return process;
}
/**
* Creates a process definition using an XML process definition file.
*
* @param xmlDefUrl
* the URL of the XML process definition file
* @return a process definition
*/
public static ProcessDefinition createProcessFromXmlDefFile(final URL xmlDefUrl) {
final Parse parse = new XmlDefParser().createParse();
parse.setUrl(xmlDefUrl);
final ProcessDefinition process = (ProcessDefinition) parse.execute().getDocumentObject();
Misc.showProblems(parse.getProblems(), "xml file");
Misc.badStateIfNull(process, "Ouch! The returned client process is null!");
return process;
}
private ProcessBuilder(final String processame, final String processVersion) {
problems = new ArrayList();
stack = new Stack();
Misc.checkArgsNotNull(processame);
ProcessDefinition process = null;
if ("".equals(processame.trim())) {
problems.add(new Problem("Process name is an empty string.", Problem.SEVERITY_ERROR));
}
if (processVersion == null || "".equals(processVersion.trim())) {
process = new ProcessDefinitionImpl(processame, "1.0");
} else {
process = new ProcessDefinitionImpl(processame, processVersion);
}
push(process);
}
/**
* Adds a description to the current BPM entity.
*
* @param description
* the BPM entity description
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDescription(final String description) {
final Object obj = peek(DescriptionElementImpl.class);
if (isDescriptionElement(obj)) {
((DescriptionElementImpl) obj).setDescription(description);
} else {
problems.add(new Problem("Unable to set description " + description + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a label to the current BPM entity.
*
* @param label
* the BPM label
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addLabel(final String label) {
final Object obj = peek(NamedElementImpl.class);
if (isNamedElement(obj)) {
((NamedElementImpl) obj).setLabel(label);
} else {
problems.add(new Problem("Unable to set label " + label + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a Character variable to the current BPM entity. This entity must be
* the process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addCharData(final String dataName) {
return addCharData(dataName, (Character) null);
}
/**
* Adds a Short variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addShortData(final String dataName) {
return addShortData(dataName, (Short) null);
}
/**
* Adds a Long variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addLongData(final String dataName) {
return addLongData(dataName, (Long) null);
}
/**
* Adds a Double variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDoubleData(final String dataName) {
return addDoubleData(dataName, (Double) null);
}
/**
* Adds a Float variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addFloatData(final String dataName) {
return addFloatData(dataName, (Float) null);
}
/**
* Adds a Boolean variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addBooleanData(final String dataName) {
return addBooleanData(dataName, (Boolean) null);
}
/**
* Adds a Integer variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addIntegerData(final String dataName) {
return addIntegerData(dataName, (Integer) null);
}
/**
* Adds a String variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addStringData(final String dataName) {
return addStringData(dataName, null);
}
/**
* Adds a XML variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addXMLData(final String dataName) {
return addXMLData(dataName, (Document) null);
}
/**
* Adds a Date variable to the current BPM entity. This entity must be the
* process itself or a process activity.
*
* @param dataName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDateData(final String dataName) {
return addDateData(dataName, (Date) null);
}
/**
* Adds a Character variable to the current BPM entity with an initial
* variable. This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the character value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addCharData(final String dataName, final Character initialValue) {
return addObjectData(dataName, Character.class.getName(), initialValue);
}
/**
* Adds a Character variable to the current BPM entity. This entity must be
* the process itself or a process activity. The scriptingValue
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addCharData(final String dataName, final String scriptingValue) {
return addObjectData(dataName, Character.class.getName(), scriptingValue);
}
/**
* Adds a Short variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the short value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addShortData(final String dataName, final Short initialValue) {
return addObjectData(dataName, Short.class.getName(), initialValue);
}
/**
* Adds a Short variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addShortData(final String dataName, final String scriptingValue) {
return addObjectData(dataName, Short.class.getName(), scriptingValue);
}
/**
* Adds a Long variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the long value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addLongData(final String dataName, final Long initialValue) {
return addObjectData(dataName, Long.class.getName(), initialValue);
}
/**
* Adds a Long variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addLongData(final String dataName, final String scriptingValue) {
return addObjectData(dataName, Long.class.getName(), scriptingValue);
}
/**
* Adds a Double variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the double value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDoubleData(final String dataName, final Double initialValue) {
return addObjectData(dataName, Double.class.getName(), initialValue);
}
/**
* Adds a Double variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDoubleData(final String dataName, final String scriptingValue) {
return addObjectData(dataName, Double.class.getName(), scriptingValue);
}
/**
* Adds a Float variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the float value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addFloatData(final String dataName, final Float initialValue) {
return addObjectData(dataName, Float.class.getName(), initialValue);
}
/**
* Adds a Float variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addFloatData(final String dataName, final String scriptingValue) {
return addObjectData(dataName, Float.class.getName(), scriptingValue);
}
/**
* Adds a Boolean variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the boolean value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addBooleanData(final String dataName, final Boolean initialValue) {
return addObjectData(dataName, Boolean.class.getName(), initialValue);
}
/**
* Adds a Boolean variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addBooleanData(final String dataName, final String scriptingValue) {
return addObjectData(dataName, Boolean.class.getName(), scriptingValue);
}
/**
* Adds an Integer variable to the current BPM entity with an initial
* variable. This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the integer value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addIntegerData(final String dataName, final Integer initialValue) {
return addObjectData(dataName, Integer.class.getName(), initialValue);
}
/**
* Adds an Integer variable to the current BPM entity with an initial
* variable. This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addIntegerData(final String dataName, final String scriptingValue) {
return addObjectData(dataName, Integer.class.getName(), scriptingValue);
}
/**
* Adds a String variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the string value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addStringData(final String dataName, final String initialValue) {
return addObjectData(dataName, String.class.getName(), (Object) initialValue);
}
/**
* Adds a XML variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the string value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addXMLData(final String dataName, final String initialValue) {
Document doc = null;
if (initialValue != null) {
try {
doc = Misc.generateDocument(initialValue);
} catch (final Exception e) {
throw new BonitaRuntimeException("Unable to generate Document from String: " + initialValue);
}
}
return addObjectData(dataName, Document.class.getName(), doc);
}
/**
* Adds a XML variable to the current BPM entity with an initial variable
* based on a script. This entity must be the process itself or a process
* activity.
*
* @param dataName
* the variable name
* @param scriptValue
* the script value. This script must generate a text representing an
* XML
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addXMLDataFromScript(final String dataName, final String scriptValue) {
return addObjectData(dataName, Document.class.getName(), scriptValue);
}
/**
* Adds a XML variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the string value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addXMLData(final String dataName, final Document initialValue) {
return addObjectData(dataName, Document.class.getName(), initialValue);
}
/**
* Adds a String variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addStringDataFromScript(final String dataName, final String scriptingValue) {
return addObjectData(dataName, String.class.getName(), scriptingValue);
}
/**
* Adds a Date variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param initialValue
* the date value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDateData(final String dataName, final Date initialValue) {
return addObjectData(dataName, Date.class.getName(), initialValue);
}
/**
* Adds a Date variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDateData(final String dataName, final String scriptingValue) {
return addObjectData(dataName, Date.class.getName(), scriptingValue);
}
/**
* Adds an Enumeration variable to the current BPM entity with an initial
* variable. This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param enumeariontValues
* the value of each enumeration member
* @param initialValue
* the initial enumeration value
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addEnumData(final String dataName, final Set enumeariontValues,
final String initialValue) {
return addObjectData(dataName, String.class.getName(), initialValue, null, enumeariontValues);
}
/**
* Adds an Enumeration variable to the current BPM entity with an initial
* variable. This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param scriptingValue
* the Groovy expression as initial value
* @param enumeariontValues
* the value of each enumeration member
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addEnumData(final String dataName, final String scriptingValue,
final Set enumeariontValues) {
return addObjectData(dataName, String.class.getName(), null, scriptingValue, enumeariontValues);
}
/**
* Adds an attachment on a process.
*
* @param name
* the attachment name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addAttachment(final String name) {
return addAttachment(name, null, null);
}
/**
* Adds an attachment on a process.
*
* @param name
* the attachment name
* @param filePath
* the attachment file path
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addAttachment(final String name, final String filePath) {
return addAttachment(name, filePath, null);
}
/**
* Adds an attachment on a process.
*
* @param name
* the attachment name
* @param filePath
* the attachment file path
* @param fileName
* the attachment file name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addAttachment(final String name, final String filePath, final String fileName) {
Misc.checkArgsNotNull(name);
if ("".equals(name.trim())) {
problems.add(new Problem("Attachment name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final AttachmentDefinitionImpl attachment = new AttachmentDefinitionImpl(process.getUUID(), name);
attachment.setFilePath(filePath);
attachment.setFileName(fileName);
process.addAttachment(attachment);
push(attachment);
}
return this;
}
private ProcessBuilder addObjectData(final String dataName, final String dataTypeClassName,
final Object initialValue, final String scriptingValue, final Set enumerationValues) {
Misc.checkArgsNotNull(dataName, dataTypeClassName);
if ("".equals(dataName.trim())) {
problems.add(new Problem("Data name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(dataTypeClassName.trim())) {
problems.add(new Problem("Data type class name is an empty string.", Problem.SEVERITY_ERROR));
}
if (initialValue != null && scriptingValue != null) {
problems.add(new Problem("Either the initial value or the scripting value must be set.", Problem.SEVERITY_ERROR));
}
if (scriptingValue != null && !Misc.isJustAGroovyExpression(scriptingValue)) {
problems.add(new Problem("The scripting value must be a groovy expression.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
DataFieldDefinitionImpl data = null;
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
data = new DataFieldDefinitionImpl(activity.getProcessDefinitionUUID(), activity.getUUID(), dataName,
dataTypeClassName);
activity.addData(data);
push(data);
} else if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
data = new DataFieldDefinitionImpl(process.getUUID(), dataName, dataTypeClassName);
process.addData(data);
push(data);
}
if (initialValue != null) {
if (!(initialValue instanceof Serializable)) {
throw new BonitaRuntimeException("Unable to store initialValue for data: " + dataTypeClassName
+ ". The given initialValue must be serializable.");
}
Class> clazz = null;
try {
clazz = Thread.currentThread().getContextClassLoader().loadClass(dataTypeClassName);
} catch (final ClassNotFoundException e) {
throw new BonitaRuntimeException("Unable to load data type class: " + dataTypeClassName);
}
if (!clazz.isAssignableFrom(initialValue.getClass())) {
throw new BonitaRuntimeException("Unable to store initialValue for data: " + dataTypeClassName
+ ". The given initialValue does not correspond to the given data type className.");
}
}
data.setInitialValue((Serializable) initialValue);
data.setEnumerationValues(enumerationValues);
data.setScriptingValue(scriptingValue);
return this;
}
/**
* Adds an Object variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param dataTypeClassName
* the data type class name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addObjectData(final String dataName, final String dataTypeClassName) {
return addObjectData(dataName, dataTypeClassName, null, null, null);
}
/**
* Adds an Object variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param dataTypeClassName
* the variable type class name
* @param initialValue
* the initial value of the variable
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addObjectData(final String dataName, final String dataTypeClassName, final Object initialValue) {
return addObjectData(dataName, dataTypeClassName, initialValue, null, null);
}
/**
* Adds an Object variable to the current BPM entity with an initial variable.
* This entity must be the process itself or a process activity.
*
* @param dataName
* the variable name
* @param dataTypeClassName
* the variable type class name
* @param scriptingValue
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addObjectData(final String dataName, final String dataTypeClassName, final String scriptingValue) {
return addObjectData(dataName, dataTypeClassName, null, scriptingValue, null);
}
/**
* Adds a group.
*
* @param groupName
* the group name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addGroup(final String groupName) {
Misc.checkArgsNotNull(groupName);
if ("".equals(groupName.trim())) {
problems.add(new Problem("Group name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ParticipantDefinitionImpl group = new ParticipantDefinitionImpl(process.getUUID(), groupName);
process.addGroup(group);
push(group);
} else {
problems.add(new Problem("Unable to add group " + groupName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a {@link RoleResolver} to a group.
*
* @param groupResolverClassName
* the {@link RoleResolver} class name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addGroupResolver(final String groupResolverClassName) {
Misc.checkArgsNotNull(groupResolverClassName);
if ("".equals(groupResolverClassName.trim())) {
problems.add(new Problem("Resolver class name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ParticipantDefinitionImpl.class);
if (isParticipant(obj)) {
final ParticipantDefinitionImpl group = (ParticipantDefinitionImpl) obj;
final RoleMapperDefinition resolver = new ConnectorDefinitionImpl(groupResolverClassName);
group.setResolver(resolver);
final ProcessDefinitionImpl process = getProcess();
process.addGroup(group);
push(group);
push(resolver);
} else {
problems.add(new Problem("Unable to add resolver " + groupResolverClassName + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a human to a process.
*
* @param humanName
* the human name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addHuman(final String humanName) {
Misc.checkArgsNotNull(humanName);
if ("".equals(humanName.trim())) {
problems.add(new Problem("Human name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ParticipantDefinitionImpl group = new ParticipantDefinitionImpl(process.getUUID(), humanName);
process.addGroup(group);
push(group);
} else {
problems.add(new Problem("Unable to add human " + humanName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Defines that the current process is an event sub-process.
*
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder setEventSubProcess() {
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
process.setType(ProcessType.EVENT_SUB_PROCESS);
} else {
problems.add(new Problem("Unable to define that the process is a sub-process on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
public ProcessBuilder setTransient() {
final Object obj = peek(DataFieldDefinitionImpl.class);
if (isDataFieldDefinition(obj)) {
final DataFieldDefinitionImpl data = (DataFieldDefinitionImpl) obj;
data.setTransient(true);
} else {
problems.add(new Problem("Unable to define as transient an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a system task. By default The join type is XOR and the split types is
* AND.
*
* @param taskName
* the system task name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addSystemTask(final String taskName) {
Misc.checkArgsNotNull(taskName);
if ("".equals(taskName.trim())) {
problems.add(new Problem("Task name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createAutomaticActivity(process.getUUID(),
taskName);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add system task " + taskName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a human task. By default The join type is XOR and the split types is
* AND.
*
* @param taskName
* the human task name
* @param authorityNames
* the group name(s) or a user name(s)
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addHumanTask(final String taskName, final String... authorityNames) {
Misc.checkArgsNotNull(taskName, authorityNames);
if ("".equals(taskName.trim())) {
problems.add(new Problem("Task name is an empty string.", Problem.SEVERITY_ERROR));
}
for (final String authorityName : authorityNames) {
if ("".equals(authorityName.trim())) {
problems.add(new Problem("Authority name is an empty string.", Problem.SEVERITY_ERROR));
}
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final Set groups = new HashSet();
for (final String authorityName : authorityNames) {
groups.add(authorityName);
}
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createHumanActivity(process.getUUID(), taskName,
groups);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add human task " + taskName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
public ProcessBuilder addEventSubProcess(final String processName, final String version) {
if ("".equals(processName.trim())) {
problems.add(new Problem("Event sub-process name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final EventProcessDefinitionImpl event = new EventProcessDefinitionImpl(processName, version);
process.addEventSubProcess(event);
push(event);
} else {
problems.add(new Problem("Unable to add an event sub process " + processName + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a sub-process. By default The join type is XOR and the split types is
* AND.
*
* @param taskName
* the task name
* @param processName
* the sub-process name.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addSubProcess(final String taskName, final String processName) {
return addSubProcess(taskName, processName, null);
}
/**
* Adds a sub-process. By default The join type is XOR and the split types is
* AND.
*
* @param taskName
* the task name
* @param processName
* the sub-process name.
* @param version
* the sub-process version.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addSubProcess(final String taskName, final String processName, final String version) {
Misc.checkArgsNotNull(taskName);
if ("".equals(taskName.trim())) {
problems.add(new Problem("Task name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(processName.trim())) {
problems.add(new Problem("Subprocess name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createSubflowActivity(process.getUUID(), taskName,
processName, version);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add sub process " + taskName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds an input parameter on the current sub-process entity.
*
* @param parentProcessDatafieldName
* the parent process variable name
* @param subProcessDatafieldName
* the sub-process variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addSubProcessInParameter(final String parentProcessDatafieldName,
final String subProcessDatafieldName) {
Misc.checkArgsNotNull(parentProcessDatafieldName, subProcessDatafieldName);
if ("".equals(parentProcessDatafieldName.trim())) {
problems.add(new Problem("Parent process datafield name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(subProcessDatafieldName.trim())) {
problems.add(new Problem("Sub process datafield name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
activity.addSubflowInParameter(new SubflowParameterDefinitionImpl(parentProcessDatafieldName,
subProcessDatafieldName));
} else {
problems.add(new Problem("Unable to add sub process parameter {" + parentProcessDatafieldName + ", "
+ subProcessDatafieldName + "} on an object of type: " + getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds an output parameter on the current sub-process entity.
*
* @param parentProcessDatafieldName
* the parent process variable name
* @param subProcessDatafieldName
* the sub-process variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addSubProcessOutParameter(final String subProcessDatafieldName,
final String parentProcessDatafieldName) {
Misc.checkArgsNotNull(parentProcessDatafieldName, subProcessDatafieldName);
if ("".equals(subProcessDatafieldName.trim())) {
problems.add(new Problem("Sub process datafield name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(parentProcessDatafieldName.trim())) {
problems.add(new Problem("Parent process datafield name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
activity.addSubflowOutParameter(new SubflowParameterDefinitionImpl(subProcessDatafieldName,
parentProcessDatafieldName));
} else {
problems.add(new Problem("Unable to add sub process parameter {" + parentProcessDatafieldName + ", "
+ subProcessDatafieldName + "} on an object of type: " + getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a decision node to the ProcessBuilder. By default The join type is XOR
* and the split types is AND.
*
* @param taskName
* the decision node name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDecisionNode(final String taskName) {
Misc.checkArgsNotNull(taskName);
if ("".equals(taskName.trim())) {
problems.add(new Problem("Task name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createAutomaticActivity(process.getUUID(),
taskName);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add decision node " + taskName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a deadline to the current activity. If the deadline fails during
* execution an exception is thrown.
*
* @param condition
* the deadline condition.
* @param connectorClassName
* the {@link Connector} class name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDeadline(final String condition, final String connectorClassName) {
return addDeadline(condition, connectorClassName, true);
}
/**
* Add a deadline to the current activity.
*
* @param condition
* the deadline condition.
* @param connectorClassName
* the {@link Connector} class name
* @param throwingException
* define whether an exception is thrown if an exception occurs
* during deadline execution
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDeadline(final String condition, final String connectorClassName,
final boolean throwingException) {
Misc.checkArgsNotNull(condition, connectorClassName);
if ("".equals(condition.trim())) {
problems.add(new Problem("Condition is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(connectorClassName.trim())) {
problems.add(new Problem("Connector class name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
if (!Misc.isJustAGroovyExpression(condition)) {
// check the deadline condition:
try {
Long.parseLong(condition);
} catch (final NumberFormatException e1) {
try {
DateUtil.parseDate(condition);
} catch (final IllegalArgumentException e2) {
problems.add(new Problem("deadline condition '" + condition + "' is neither a Long nor a formatted date",
Problem.SEVERITY_ERROR));
}
}
}
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
final ConnectorDefinitionImpl deadline = new ConnectorDefinitionImpl(connectorClassName);
deadline.setCondition(condition);
deadline.setThrowingException(throwingException);
activity.addDeadline(deadline);
push(deadline);
} else {
problems.add(new Problem("Unable to add a deadline with condition " + condition + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a connector to an activity or a process.
*
* @param className
* the connector class name
* @param event
* the connector event
* @param throwingException
* if the connector throws exception
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addConnector(final Event event, final String className, final boolean throwingException) {
Misc.checkArgsNotNull(className, event);
if ("".equals(className.trim())) {
problems.add(new Problem("Class name is an empty string.", Problem.SEVERITY_ERROR));
}
Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
if (activity.isTimer()) {
if (!Event.onTimer.equals(event)) {
problems.add(new Problem("A timer task accepts only a connector with an " + Event.onTimer + " event" + " ",
Problem.SEVERITY_ERROR));
}
} else if (activity.isAutomatic()) {
if (!(Event.automaticOnEnter.equals(event) || Event.automaticOnExit.equals(event))) {
problems.add(new Problem("An automatic activity accepts only a connector with an " + Event.automaticOnEnter
+ " or an " + Event.automaticOnExit + " event" + " ", Problem.SEVERITY_ERROR));
}
} else if (activity.isSubflow()) {
if (!(Event.automaticOnEnter.equals(event) || Event.automaticOnExit.equals(event))) {
problems.add(new Problem("A sub process accepts only a connector with an " + Event.automaticOnEnter
+ " or an " + Event.automaticOnExit + " event" + " ", Problem.SEVERITY_ERROR));
}
} else {
if (!Event.TASK_EVENTS.contains(event)) {
problems.add(new Problem("A human task accepts only a connector with an event of this list: "
+ Event.TASK_EVENTS, Problem.SEVERITY_ERROR));
}
}
final ConnectorDefinitionImpl connector = new ConnectorDefinitionImpl(className);
connector.setEvent(event);
connector.setThrowingException(throwingException);
activity.addConnector(connector);
push(connector);
} else {
obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
if (!Event.PROCESS_EVENTS.contains(event)) {
problems.add(new Problem("A process accepts only a connector with an event of this list: "
+ Event.PROCESS_EVENTS, Problem.SEVERITY_ERROR));
}
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ConnectorDefinitionImpl connector = new ConnectorDefinitionImpl(className);
connector.setEvent(event);
connector.setThrowingException(throwingException);
process.addConnector(connector);
push(connector);
} else {
problems.add(new Problem("Unable to add a connector with class " + className + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
}
return this;
}
/**
* Adds an input parameter on the current connector.
*
* @param fieldName
* a connector field name
* @param value
* the value(s) to set
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addInputParameter(final String fieldName, final Object... value) {
Misc.checkArgsNotNull(fieldName);
if ("".equals(fieldName.trim())) {
problems.add(new Problem("Connector field name is an empty string.", Problem.SEVERITY_ERROR));
}
String setterName = null;
if (fieldName.startsWith("set") || fieldName.startsWith("get") || fieldName.startsWith("is")
|| "file:".equals(fieldName) || "resource:".equals(fieldName) || "bar:".equals(fieldName)) {
setterName = fieldName;
} else {
final StringBuilder builder = new StringBuilder("set");
builder.append(String.valueOf(fieldName.charAt(0)).toUpperCase());
builder.append(fieldName.substring(1));
setterName = builder.toString();
}
return setParameter(setterName, value);
}
/**
* @see #addInputParameter(String, Object...)
*/
@Deprecated
public ProcessBuilder addParameter(final String fieldName, final Object... value) {
return addInputParameter(fieldName, value);
}
/**
* Adds an output parameter on the current connector. The result of Groovy
* expression (containing getter fields) will be set in the variable name.
*
* @param groovyExpression
* the Groovy expression.
* @param variableName
* the variable name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addOutputParameter(String groovyExpression, final String variableName) {
Misc.checkArgsNotNull(groovyExpression, variableName);
if ("".equals(groovyExpression.trim())) {
problems.add(new Problem("Connector field name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(variableName.trim())) {
problems.add(new Problem("Connector field name is an empty string.", Problem.SEVERITY_ERROR));
}
if (!GroovyExpression.isGroovyExpression(groovyExpression)) {
final StringBuilder builder = new StringBuilder(GroovyExpression.START_DELIMITER);
builder.append(groovyExpression);
builder.append(GroovyExpression.END_DELIMITER);
groovyExpression = builder.toString();
}
return setParameter(variableName, groovyExpression);
}
private ProcessBuilder setParameter(final String setterOrGetterName, final Object... value) {
Misc.checkArgsNotNull(setterOrGetterName, value);
if ("".equals(setterOrGetterName.trim())) {
problems.add(new Problem("Setter/Getter name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ConnectorDefinitionImpl.class);
if (isConnector(obj)) {
((ConnectorDefinitionImpl) obj).addParameter(setterOrGetterName, value);
} else {
problems.add(new Problem("Unable to add a parameter with field " + setterOrGetterName + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a filter to an activity (A filter is a specific connector)
*
* @param className
* the filter class name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addFilter(final String className) {
Misc.checkArgsNotNull(className);
if ("".equals(className.trim())) {
problems.add(new Problem("Filter class name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
final FilterDefinition filter = new ConnectorDefinitionImpl(className);
activity.setFilter(filter);
push(filter);
} else {
problems.add(new Problem("Unable to add a filter with class name " + className + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a multiInstantiation to an activity.
*
* @param variableName
* the variable name
* @param className
* the multi-instantiation class name
* @return the ProcessBuilder in order to add BPM elements
*/
@Deprecated
public ProcessBuilder addMultiInstanciation(final String variableName, final String className) {
Misc.checkArgsNotNull(className, variableName);
if ("".equals(variableName.trim())) {
problems.add(new Problem("Multi instantiation variable name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(className.trim())) {
problems.add(new Problem("Multi instantiation class name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
final ConnectorDefinitionImpl multiInstanciation = new ConnectorDefinitionImpl(className);
multiInstanciation.setVariableName(variableName);
activity.setMultiInstanciation(multiInstanciation);
push(multiInstanciation);
} else {
problems.add(new Problem("Unable to add a multi instantiation with variable name " + variableName
+ " on an object of type: " + getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
public ProcessBuilder addMultipleActivitiesInstantiator(final String className) {
Misc.checkArgsNotNull(className);
if ("".equals(className.trim())) {
problems.add(new Problem("Multiple Activities Instantiator class name is an empty string.",
Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
final ConnectorDefinitionImpl instantiator = new ConnectorDefinitionImpl(className);
activity.setMultipleInstancesInstantiator(instantiator);
push(instantiator);
} else {
problems.add(new Problem("Unable to add a multiple activities instantiatior with class name " + className
+ " on an object of type: " + getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
public ProcessBuilder addMultipleActivitiesJoinChecker(final String className) {
Misc.checkArgsNotNull(className);
if ("".equals(className.trim())) {
problems.add(new Problem("Multiple Activities Join Checker class name is an empty string.",
Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
final ConnectorDefinitionImpl joinChecker = new ConnectorDefinitionImpl(className);
activity.setMultipleInstancesJoinChecker(joinChecker);
push(joinChecker);
} else {
problems.add(new Problem("Unable to add a multiple activities join checker with class name " + className
+ " on an object of type: " + getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Defines that the current activity is asynchronous.
*
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder asynchronous() {
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
activity.setAsynchronous(true);
} else {
problems.add(new Problem("Unable to set asynchronous on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Defines the join type of an activity.
*
* @param join
* the join type
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addJoinType(final JoinType join) {
Misc.checkArgsNotNull(join);
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
activity.setJoinType(join);
} else {
problems.add(new Problem("Unable to set join type " + join + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Defines the split type of an activity
*
* @param split
* the split type
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addSplitType(final SplitType split) {
Misc.checkArgsNotNull(split);
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
activity.setSplitType(split);
} else {
problems.add(new Problem("Unable to set split type " + split + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a dynamic description to the current BPM entity.
*
* @param dynamicDescription
* the BPM entity dynamicDescription
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDynamicDescription(final String dynamicDescription) {
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
((ActivityDefinitionImpl) obj).setDynamicDescription(dynamicDescription);
} else {
problems.add(new Problem("Unable to set dynamicDescription " + dynamicDescription + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a dynamic label to the current BPM entity.
*
* @param dynamicLabel
* the BPM entity dynamicLabel
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDynamicLabel(final String dynamicLabel) {
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
((ActivityDefinitionImpl) obj).setDynamicLabel(dynamicLabel);
} else {
problems.add(new Problem(
"Unable to set dynamicLabel " + dynamicLabel + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a dynamic execution summary to the current BPM entity.
*
* @param expression
* the dynamic expression
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addDynamicExecutionSummary(final String expression) {
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
((ActivityDefinitionImpl) obj).setDynamicExecutionSummary(expression);
} else {
problems.add(new Problem("Unable to set the dynamic execution summary " + expression + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a category defining the process
*
* @param category
* the category name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addCategory(final String category) {
Misc.checkArgsNotNull(category);
if ("".equals(category.trim())) {
problems.add(new Problem("Category name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
process.addCategory(category);
} else {
problems.add(new Problem("Unable to add category " + category + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a timer.
*
* @param taskName
* the timer name.
* @param condition
* the timer condition.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addTimerTask(final String taskName, final String condition) {
Misc.checkArgsNotNull(taskName);
if ("".equals(taskName.trim())) {
problems.add(new Problem("Task name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(condition.trim())) {
problems.add(new Problem("Timer condition name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createTimerActivity(process.getUUID(), taskName,
condition);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add timer task " + taskName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a received event task.
*
* @param taskName
* the task name
* @param eventName
* the event name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addReceiveEventTask(final String taskName, final String eventName) {
return addReceiveEventTask(taskName, eventName, null);
}
/**
* Adds a received event task.
*
* @deprecated replaced by {@link #addReceiveEventTask(String, String)} and
* {@link #addMessageCorrelationKey(String, String)}
* @param taskName
* the task name
* @param eventName
* the event name
* @param expression
* the expression
* @return the ProcessBuilder in order to add BPM elements
*/
@Deprecated
public ProcessBuilder addReceiveEventTask(final String taskName, final String eventName, final String expression) {
Misc.checkArgsNotNull(taskName);
if ("".equals(taskName.trim())) {
problems.add(new Problem("Task name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(eventName.trim())) {
problems.add(new Problem("Event name is an empty string.", Problem.SEVERITY_ERROR));
}
if (expression != null && "".equals(expression.trim())) {
problems.add(new Problem("Expression is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createReceiveEventActivity(process.getUUID(),
taskName, eventName, expression);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add receive event task " + taskName + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a connector to the current received event.
*
* @param className
* the connector class name
* @param throwingException
* if the connector throws exception.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addReceiveEventConnector(final String className, final boolean throwingException) {
Misc.checkArgsNotNull(className);
if ("".equals(className.trim())) {
problems.add(new Problem("Class name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
final ConnectorDefinitionImpl connector = new ConnectorDefinitionImpl(className);
connector.setEvent(Event.onEvent);
connector.setThrowingException(throwingException);
activity.addConnector(connector);
push(connector);
} else {
problems.add(new Problem("Unable to add an event connector with class " + className + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add to the current connector of an activity the possibility to throw an
* error event.
*
* @param errorCode
* the error code of the event to throw.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder throwCatchError(final String errorCode) {
Misc.checkArgsNotNull(errorCode);
if ("".equals(errorCode.trim())) {
problems.add(new Problem("Connector errorCode is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ConnectorDefinitionImpl.class);
if (isConnector(obj)) {
((ConnectorDefinitionImpl) obj).setErrorCode(errorCode);
} else {
problems.add(new Problem("Unable to add an errorCode: " + errorCode + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a end error event task.
*
* @param eventName
* the name of event.
* @param errorCode
* the error code of the event.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addErrorEventTask(final String eventName, final String errorCode) {
Misc.checkArgsNotNull(eventName, errorCode);
if ("".equals(eventName.trim())) {
problems.add(new Problem("Event name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(errorCode.trim())) {
problems.add(new Problem("Error code is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createErrorEventActivity(process.getUUID(),
eventName, errorCode);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add an error event task " + eventName + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a throwing signal event task.
*
* @param eventName
* the name of event.
* @param signalCode
* the signal code of the event.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addSignalEventTask(final String eventName, final String signalCode) {
return addSignalEventTask(eventName, signalCode, false);
}
public ProcessBuilder addSignalEventTask(final String eventName, final String signalCode, final boolean catchEvent) {
Misc.checkArgsNotNull(eventName, signalCode);
if ("".equals(eventName.trim())) {
problems.add(new Problem("Event name is an empty string.", Problem.SEVERITY_ERROR));
}
if ("".equals(signalCode.trim())) {
problems.add(new Problem("Signal code is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createSignalEventActivity(process.getUUID(),
eventName, signalCode);
activity.setCatchEvent(catchEvent);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add an error event task " + eventName + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a signal boundary event onto an activity.
*
* @param eventName
* the name of the event.
* @param signalCode
* the expression of the event.
* @return the ProcessBuilder in order to add BPM elements.
*/
public ProcessBuilder addSignalBoundaryEvent(final String eventName, final String signalCode) {
Misc.checkArgsNotNull(eventName);
if ("".equals(eventName.trim())) {
problems.add(new Problem("Event name is an empty string.", Problem.SEVERITY_ERROR));
}
if (signalCode != null && "".equals(signalCode.trim())) {
problems.add(new Problem("Expression is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
if (canAddBoundaryEvent(activity, "signal")) {
final SignalBoundaryEventImpl message = new SignalBoundaryEventImpl(eventName,
activity.getProcessDefinitionUUID(), activity.getUUID(), null, signalCode);
activity.addBoundaryEvent(message);
push(message);
} else {
problems.add(new Problem(
"Unable to add a boundary message event on an activity of type: " + activity.getType(),
Problem.SEVERITY_ERROR));
}
} else {
problems.add(new Problem("Unable to add a boundary message event on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
private EventDefinitionImpl getEventDefinition(final String name) {
final Object obj = stack.peek();
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
if (activity.isReceiveEvent()) {
final IncomingEventDefinition incomingEvent = activity.getIncomingEvent();
if (incomingEvent.getExpression() != null) {
problems.add(new Problem("A correlation key cannot be added when an expression is set.",
Problem.SEVERITY_ERROR));
}
return (IncomingEventDefinitionImpl) incomingEvent;
} else if (activity.isSendEvents()) {
return outgoingEvent;
} else {
problems.add(new Problem("Unable to add a correlation key " + name + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
} else {
problems.add(new Problem("Unable to add a correlation key " + name + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return null;
}
private MessageBoundaryEventImpl getMessageBoundaryEvent(final String name) {
final Object obj = stack.peek();
if (isMessageBoundaryEvent(obj)) {
final MessageBoundaryEventImpl messageEvent = (MessageBoundaryEventImpl) obj;
if (messageEvent.getExpression() != null) {
problems
.add(new Problem("A correlation key cannot be added when an expression is set.", Problem.SEVERITY_ERROR));
}
return messageEvent;
}
return null;
}
public ProcessBuilder addMessageCorrelationKey(final String name, final String expression) {
Misc.checkArgsNotNull(name, expression);
if ("".equals(name.trim())) {
problems.add(new Problem("Correlation key name is an empty string.", Problem.SEVERITY_ERROR));
}
final MessageBoundaryEventImpl messageEvent = getMessageBoundaryEvent(name);
if (messageEvent != null) {
if (messageEvent.getCorrelationKeyName1() == null) {
messageEvent.setCorrelationKey1(name, expression);
} else if (messageEvent.getCorrelationKeyName2() == null) {
messageEvent.setCorrelationKey2(name, expression);
} else if (messageEvent.getCorrelationKeyName3() == null) {
messageEvent.setCorrelationKey3(name, expression);
} else if (messageEvent.getCorrelationKeyName4() == null) {
messageEvent.setCorrelationKey4(name, expression);
} else if (messageEvent.getCorrelationKeyName5() == null) {
messageEvent.setCorrelationKey5(name, expression);
} else {
problems.add(new Problem("5 Correlation keys are already set on " + messageEvent.getName(),
Problem.SEVERITY_ERROR));
}
} else {
final EventDefinitionImpl event = getEventDefinition(name);
if (event.getCorrelationKeyName1() == null) {
event.setCorrelationKey1(name, expression);
} else if (event.getCorrelationKeyName2() == null) {
event.setCorrelationKey2(name, expression);
} else if (event.getCorrelationKeyName3() == null) {
event.setCorrelationKey3(name, expression);
} else if (event.getCorrelationKeyName4() == null) {
event.setCorrelationKey4(name, expression);
} else if (event.getCorrelationKeyName5() == null) {
event.setCorrelationKey5(name, expression);
} else {
problems.add(new Problem("5 Correlation keys are already set on " + event.getName(), Problem.SEVERITY_ERROR));
}
}
return this;
}
/**
* Adds a send event task.
*
* @param taskName
* the task name.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addSendEventTask(final String taskName) {
Misc.checkArgsNotNull(taskName);
if ("".equals(taskName.trim())) {
problems.add(new Problem("Task name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createSendEventActivity(process.getUUID(),
taskName);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add send event task " + taskName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds an outgoing event on the current activity.
*
* @param eventName
* the event name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addOutgoingEvent(final String eventName) {
return addOutgoingEvent(eventName, null);
}
/**
* Adds an outgoing event on the current activity.
*
* @param eventName
* the event name
* @param destProcessName
* the destination process
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addOutgoingEvent(final String eventName, final String destProcessName) {
return addOutgoingEvent(eventName, destProcessName, null);
}
/**
* Adds an outgoing event on the current activity.
*
* @param eventName
* the event name
* @param destProcessName
* the destination process
* @param destActivityName
* the destination activity
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addOutgoingEvent(final String eventName, final String destProcessName,
final String destActivityName) {
return addOutgoingEvent(eventName, destProcessName, destActivityName, null);
}
/**
* Adds an outgoing event on the current activity.
*
* @param eventName
* the event name
* @param destProcessName
* the destination process
* @param destActivityName
* the destination activity
* @param parameters
* the parameters to transfer
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addOutgoingEvent(final String eventName, final String destProcessName,
final String destActivityName, final Map parameters) {
return addOutgoingEvent(eventName, destProcessName, destActivityName, -1, parameters);
}
/**
* Adds an outgoing event on the current activity.
*
* @param eventName
* the event name
* @param destProcessName
* the destination process
* @param destActivityName
* the destination activity
* @param timeToLive
* the time to live of this event
* @param parameters
* the parameters to transfer
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addOutgoingEvent(final String eventName, final String destProcessName,
final String destActivityName, final long timeToLive, final Map parameters) {
Misc.checkArgsNotNull(eventName);
if ("".equals(eventName.trim())) {
problems.add(new Problem("Event name is an empty string.", Problem.SEVERITY_ERROR));
}
if (destProcessName != null && "".equals(destProcessName.trim())) {
problems.add(new Problem("Dest process name is an empty string.", Problem.SEVERITY_ERROR));
}
if (destActivityName != null && "".equals(destActivityName.trim())) {
problems.add(new Problem("Dest activity name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
final OutgoingEventDefinitionImpl outgoingEvent = new OutgoingEventDefinitionImpl(eventName, destProcessName,
destActivityName, parameters, timeToLive);
activity.addOutgoingEvent(outgoingEvent);
this.outgoingEvent = outgoingEvent;
} else {
problems.add(new Problem("Unable to add outgoing event " + eventName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a terminate end event. This event ends the process execution even if
* other branches are active.
*
* @param eventName
* the event name
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addTerminateEndEvent(final String eventName) {
Misc.checkArgsNotNull(eventName);
if ("".equals(eventName.trim())) {
problems.add(new Problem("Event name is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinitionImpl activity = ActivityDefinitionImpl.createAutomaticActivity(process.getUUID(),
eventName);
activity.setTerminateProcess(true);
process.addActivity(activity);
push(activity);
} else {
problems.add(new Problem("Unable to add terminate end event " + eventName + " on an object of type: "
+ getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds an executing time (in ms) to the current activity. This time should be
* greater than 1s.
*
* @param executingTime
* the executing time of the activity
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addActivityExecutingTime(final long executingTime) {
if (executingTime < 1000) {
problems.add(new Problem("The executing time cannot be less than one second.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
activity.setExecutingTime(executingTime);
} else {
problems.add(new Problem("Unable to set an executing time on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a priority to the current activity.
*
* @param priority
* the activity priority.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addActivityPriority(final int priority) {
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
activity.setPriority(priority);
} else {
problems.add(new Problem("Unable to set a priority on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Defines that the current activity is a loop one. While the condition is
* true a new instance of the activity is created.
*
* @param condition
* a Groovy script which must return a boolean value.
* @param beforeExecution
* true if the condition is evaluated before the activity creation.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addLoop(final String condition, final boolean beforeExecution) {
return addLoop(condition, beforeExecution, null);
}
/**
* Defines that the current activity is a loop one. While the condition is
* true a new instance of the activity is created.
*
* @param condition
* a Groovy script which must return a boolean value.
* @param beforeExecution
* true if the condition is evaluated before the activity creation.
* @param loopMaximum
* the maximum number of loops.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addLoop(final String condition, final boolean beforeExecution, final String loopMaximum) {
Misc.checkArgsNotNull(condition);
if ("".equals(condition.trim())) {
problems.add(new Problem("Condition expression is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
activity.setLoop(condition, beforeExecution, loopMaximum);
} else {
problems.add(new Problem("Unable to set a loop on an object of type: " + getClass(obj), Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a timer boundary event onto an activity.
*
* @param eventName
* the name of the event.
* @param condition
* the condition of the timer event.
* @return the ProcessBuilder in order to add BPM elements.
*/
public ProcessBuilder addTimerBoundaryEvent(final String eventName, final String condition) {
Misc.checkArgsNotNull(eventName, condition);
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
if (canAddBoundaryEvent(activity, "timer")) {
final TimerBoundaryEventImpl timer = new TimerBoundaryEventImpl(eventName, activity.getProcessDefinitionUUID(),
activity.getUUID(), null, condition);
activity.addBoundaryEvent(timer);
push(timer);
} else {
problems.add(new Problem("Unable to add a boundary timer event on an activity of type: " + activity.getType(),
Problem.SEVERITY_ERROR));
}
} else {
problems.add(new Problem("Unable to add a boundary timer event on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add a message boundary event onto an activity.
*
* @param eventName
* the name of the event.
* @param expression
* the expression of the event.
* @return the ProcessBuilder in order to add BPM elements.
*/
public ProcessBuilder addMessageBoundaryEvent(final String eventName, final String expression) {
Misc.checkArgsNotNull(eventName);
if ("".equals(eventName.trim())) {
problems.add(new Problem("Event name is an empty string.", Problem.SEVERITY_ERROR));
}
if (expression != null && "".equals(expression.trim())) {
problems.add(new Problem("Expression is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
if (canAddBoundaryEvent(activity, "message")) {
final MessageBoundaryEventImpl message = new MessageBoundaryEventImpl(eventName,
activity.getProcessDefinitionUUID(), activity.getUUID(), null, expression);
activity.addBoundaryEvent(message);
push(message);
} else {
problems.add(new Problem(
"Unable to add a boundary message event on an activity of type: " + activity.getType(),
Problem.SEVERITY_ERROR));
}
} else {
problems.add(new Problem("Unable to add a boundary message event on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Add an error boundary event onto a task or a system task.
*
* @param eventName
* the name of the event
* @return the ProcessBuilder in order to add BPM elements.
*/
public ProcessBuilder addErrorBoundaryEvent(final String eventName) {
return addErrorBoundaryEvent(eventName, null);
}
/**
* Add an error boundary event onto a sub-process activity.
*
* @param eventName
* the name of the event
* @param errorCode
* the error code of the event
* @return the ProcessBuilder in order to add BPM elements.
*/
public ProcessBuilder addErrorBoundaryEvent(final String eventName, final String errorCode) {
Misc.checkArgsNotNull(eventName);
if ("".equals(eventName.trim())) {
problems.add(new Problem("Event name is an empty string.", Problem.SEVERITY_ERROR));
}
if (errorCode != null && "".equals(errorCode.trim())) {
problems.add(new Problem("Expression is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ActivityDefinitionImpl.class);
if (isActivity(obj)) {
final ActivityDefinitionImpl activity = (ActivityDefinitionImpl) obj;
if (canAddBoundaryEvent(activity, "error")) {
final ErrorBoundaryEventImpl error = new ErrorBoundaryEventImpl(eventName, activity.getProcessDefinitionUUID(),
activity.getUUID(), null, errorCode);
activity.addBoundaryEvent(error);
push(error);
} else {
problems.add(new Problem("Unable to add a boundary message event on an object of type: " + activity.getType(),
Problem.SEVERITY_ERROR));
}
} else {
problems.add(new Problem("Unable to add a boundary message event on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a transition between two activities.
*
* @param fromActivityName
* the activity name where the transition leaves
* @param toActivityName
* the activity name where the transition arrives
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addTransition(final String fromActivityName, final String toActivityName) {
return addTransition(fromActivityName + "__" + toActivityName, fromActivityName, toActivityName);
}
/**
* Adds an exception transition between a boundary event of an activity to
* another activity.
*
* @param fromActivityName
* the activity name where the boundary event is
* @param boundaryEventName
* the name of the boundary event
* @param toActivityName
* the activity name where the transition arrives
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addExceptionTransition(final String fromActivityName, final String boundaryEventName,
final String toActivityName) {
Misc.checkArgsNotNull(boundaryEventName);
return addTransition(fromActivityName + "__" + boundaryEventName + "__" + toActivityName, fromActivityName,
boundaryEventName, toActivityName);
}
/**
* Adds a transition between two activities.
*
* @param transitionName
* the transition name
* @param fromActivityName
* the activity name where the transition leaves
* @param toActivityName
* the activity name where the transition arrives
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addTransition(final String transitionName, final String fromActivityName,
final String toActivityName) {
return addTransition(transitionName, fromActivityName, null, toActivityName);
}
private ProcessBuilder addTransition(final String transitionName, final String fromActivityName,
final String boundaryEventName, final String toActivityName) {
Misc.checkArgsNotNull(transitionName, fromActivityName, toActivityName);
if ("".equals(transitionName.trim())) {
problems.add(new Problem("Transition name is an empty string.", Problem.SEVERITY_ERROR));
}
if (fromActivityName == null) {
problems
.add(new Problem("From attribute is not defined on transition: " + transitionName, Problem.SEVERITY_ERROR));
} else if ("".equals(fromActivityName.trim())) {
problems.add(new Problem("Transition from activity name is an empty string.", Problem.SEVERITY_ERROR));
}
if (toActivityName == null) {
problems.add(new Problem("To attribute is not defined on transition: " + transitionName, Problem.SEVERITY_ERROR));
} else if ("".equals(toActivityName.trim())) {
problems.add(new Problem("Transition to activity name is an empty string.", Problem.SEVERITY_ERROR));
}
if (boundaryEventName != null && "".equals(boundaryEventName.trim())) {
problems.add(new Problem("The name of the boundary event is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(ProcessDefinitionImpl.class);
if (isProcess(obj)) {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) obj;
final ActivityDefinition fromActivity = process.getActivity(fromActivityName);
BoundaryEvent event = null;
if (fromActivity != null && boundaryEventName != null) {
event = fromActivity.getBoundaryEvent(boundaryEventName);
}
final ActivityDefinition toActivity = process.getActivity(toActivityName);
if (fromActivity == null) {
problems.add(new Problem("Unable to add transition from " + fromActivityName + " to " + toActivityName
+ ". From activity does not exists", Problem.SEVERITY_ERROR));
} else if (toActivity == null) {
problems.add(new Problem("Unable to add transition from " + fromActivityName + " to " + toActivityName
+ ". To activity does not exists", Problem.SEVERITY_ERROR));
} else if (boundaryEventName != null && event == null) {
problems.add(new Problem("Unable to add an exception transition from " + fromActivityName
+ ", boundary event: " + boundaryEventName + " to " + toActivityName + ". Boundary event does not exists",
Problem.SEVERITY_ERROR));
} else {
final TransitionDefinitionImpl transition = new TransitionDefinitionImpl(process.getUUID(), transitionName,
fromActivityName, toActivityName);
((ActivityDefinitionImpl) toActivity).addIncomingTransition(transition);
if (boundaryEventName != null) {
transition.setFromBoundaryEvent(boundaryEventName);
((ActivityDefinitionImpl) fromActivity).addExceptionTransition(boundaryEventName, transition);
} else {
((ActivityDefinitionImpl) fromActivity).addOutgoingTransition(transition);
}
push(transition);
}
} else {
problems.add(new Problem(
"Unable to add transition " + transitionName + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Set the last transition as the default transition
*
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder setDefault() {
final Object obj = peek(TransitionDefinitionImpl.class);
if (isTransition(obj)) {
final TransitionDefinitionImpl transition = (TransitionDefinitionImpl) obj;
if (transition.getFromBoundaryEvent() != null) {
problems.add(new Problem("Unable to set the default exception transition '" + transition.getName()
+ "' as a default transition", Problem.SEVERITY_ERROR));
}
transition.setDefault(true);
} else {
problems.add(new Problem("Unable to set default transition on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Adds a condition on a transition
*
* @param expression
* the condition.
* @return the ProcessBuilder in order to add BPM elements
*/
public ProcessBuilder addCondition(final String expression) {
Misc.checkArgsNotNull(expression);
if ("".equals(expression.trim())) {
problems.add(new Problem("Condition expression is an empty string.", Problem.SEVERITY_ERROR));
}
final Object obj = peek(TransitionDefinitionImpl.class);
if (isTransition(obj)) {
final TransitionDefinitionImpl transition = (TransitionDefinitionImpl) obj;
if (transition.getFromBoundaryEvent() != null) {
problems.add(new Problem("Unable to set condition " + expression + " on the exception transition: "
+ transition.getName(), Problem.SEVERITY_ERROR));
}
transition.setCondition(expression);
} else {
problems.add(new Problem("Unable to set condition " + expression + " on an object of type: " + getClass(obj),
Problem.SEVERITY_ERROR));
}
return this;
}
/**
* Finishes the process definition. This method checks how the definition was
* done and throws all the errors that the process definition contains.
*
* @return the process definition ready to use.
*/
public ProcessDefinition done() {
final ProcessDefinitionImpl process = (ProcessDefinitionImpl) stack.get(0);
checkNames();
checkStartEvents(process);
checkEventSubProcess(process);
checkDefaultTransitions(process);
checkExceptionsTransitions(process);
checkMultiInstantiation(process);
checkTransientVariables();
Misc.showProblems(problems, "process builder");
setSubProcesses(process);
return process;
}
private void checkStartEvents(final ProcessDefinitionImpl process) {
for (final ActivityDefinition activity : process.getActivities()) {
if (activity.getIncomingTransitions().size() == 0) {
if (activity.isThrowingSignalEvent()) {
problems.add(new Problem("Process " + process.getName() + " cannot start with a throw signal event",
Problem.SEVERITY_ERROR));
} else if (activity.isThrowingSignalEvent()) {
problems.add(new Problem("Process " + process.getName() + " cannot start with a throw error event",
Problem.SEVERITY_ERROR));
} else if (activity.isCatchingErrorEvent() && ProcessType.PROCESS.equals(process.getType())) {
problems.add(new Problem("Process " + process.getName()
+ " cannot start with a catch error event because it is not an event sub-process.",
Problem.SEVERITY_ERROR));
}
}
}
}
private void setSubProcesses(final ProcessDefinitionImpl process) {
final Set subProcesses = new HashSet();
for (final ActivityDefinition activity : process.getActivities()) {
if (activity.isSubflow()) {
subProcesses.add(activity.getSubflowProcessName());
}
}
if (!subProcesses.isEmpty()) {
process.setSubProcesses(subProcesses);
}
}
private void checkEventSubProcess(final ProcessDefinitionImpl process) {
if (ProcessType.EVENT_SUB_PROCESS.equals(process.getType())) {
for (final ActivityDefinition activity : process.getActivities()) {
if (activity.getIncomingTransitions().size() == 0) {
if (!(activity.isTimer() || activity.isCatchingSignalEvent() || activity.isReceiveEvent() || activity
.isCatchingErrorEvent())) {
problems.add(new Problem("Process " + process.getName() + " must not begin with a \"none\" start event",
Problem.SEVERITY_ERROR));
}
}
}
}
}
private void checkDefaultTransitions(final ProcessDefinitionImpl process) {
for (final ActivityDefinition activity : process.getActivities()) {
boolean hasDefault = false;
final Set outgoingTransitions = activity.getOutgoingTransitions();
if (!outgoingTransitions.isEmpty()) {
for (final TransitionDefinition tr : activity.getOutgoingTransitions()) {
if (tr.isDefault()) {
if (hasDefault) {
problems.add(new Problem("Activity " + activity.getName() + " has multiple default outgoing transitions",
Problem.SEVERITY_ERROR));
}
if (tr.getCondition() != null) {
problems.add(new Problem("Activity " + activity.getName() + " has a default condition with a condition:"
+ tr.getName(), Problem.SEVERITY_ERROR));
}
hasDefault = true;
}
}
}
}
}
private void checkExceptionsTransitions(final ProcessDefinitionImpl process) {
for (final ActivityDefinition activity : process.getActivities()) {
final List boundaryEvents = activity.getBoundaryEvents();
for (final BoundaryEvent boundaryEvent : boundaryEvents) {
if (boundaryEvent.getTransition() == null) {
problems.add(new Problem("The boundary event '" + boundaryEvent.getName() + "' on activity '"
+ activity.getName() + "' must have an exception transition", Problem.SEVERITY_ERROR));
}
}
}
}
private void checkMultiInstantiation(final ProcessDefinitionImpl process) {
for (final ActivityDefinition activity : process.getActivities()) {
final MultiInstantiationDefinition multiInstantiationDefinition = activity.getMultiInstantiationDefinition();
final MultiInstantiationDefinition instantiator = activity.getMultipleInstancesInstantiator();
final MultiInstantiationDefinition joinChecker = activity.getMultipleInstancesJoinChecker();
if (instantiator != null || joinChecker != null || multiInstantiationDefinition != null) {
if (multiInstantiationDefinition != null) {
final String variableId = multiInstantiationDefinition.getVariableName();
boolean variableExists = false;
if (activity.getDataFields() != null) {
for (final DataFieldDefinition var : activity.getDataFields()) {
if (var.getName().equals(variableId)) {
variableExists = true;
break;
}
}
}
if (!variableExists) {
problems.add(new Problem("MultiInstantiation variable " + variableId
+ " must be a local variable of activity " + activity.getName(), Problem.SEVERITY_ERROR));
}
} else if (instantiator != null && joinChecker == null) {
problems.add(new Problem("JoinChecker is undefined", Problem.SEVERITY_ERROR));
} else if (instantiator == null && joinChecker != null) {
problems.add(new Problem("Instantiator is undefined", Problem.SEVERITY_ERROR));
}
}
}
}
private boolean isConnector(final Object obj) {
return obj instanceof ConnectorDefinitionImpl;
}
private boolean isDescriptionElement(final Object obj) {
return obj instanceof DescriptionElementImpl;
}
private boolean isNamedElement(final Object obj) {
return obj instanceof NamedElementImpl;
}
private boolean isActivity(final Object obj) {
return obj instanceof ActivityDefinitionImpl;
}
private boolean isMessageBoundaryEvent(final Object obj) {
return obj instanceof MessageBoundaryEventImpl;
}
private boolean isProcess(final Object obj) {
return obj instanceof ProcessDefinitionImpl;
}
private boolean isParticipant(final Object obj) {
return obj instanceof ParticipantDefinitionImpl;
}
private boolean isTransition(final Object obj) {
return obj instanceof TransitionDefinitionImpl;
}
private boolean isDataFieldDefinition(final Object obj) {
return obj instanceof DataFieldDefinitionImpl;
}
private ProcessDefinitionImpl getProcess() {
return (ProcessDefinitionImpl) stack.get(0);
}
private void push(final Object obj) {
stack.push(obj);
}
private Object peek(final Class> clazz) {
Misc.checkArgsNotNull(clazz);
while (stack.size() > 1) {
if (clazz.isAssignableFrom(stack.peek().getClass())) {
return stack.peek();
}
stack.pop();
}
return stack.peek();
}
private String getClass(final Object obj) {
if (obj == null) {
return null;
}
final Class> clazz = obj.getClass();
final Class>[] itf = clazz.getInterfaces();
if (itf == null || itf.length == 0) {
return clazz.toString();
}
return itf[0].getName();
}
private void checkNames() {
final ProcessDefinitionImpl definition = (ProcessDefinitionImpl) stack.get(0);
final Set groups = definition.getParticipants();
if (groups != null) {
final List groupNames = new ArrayList();
for (final ParticipantDefinition group : groups) {
final String groupName = group.getName();
if (groupNames.contains(groupName)) {
problems.add(new Problem("Impossible to have more than one group/human with the name: " + groupName,
Problem.SEVERITY_ERROR));
} else {
groupNames.add(groupName);
}
}
}
final Set processDataFields = definition.getDataFields();
final List dataFieldNames = new ArrayList();
if (processDataFields != null) {
for (final DataFieldDefinition datafield : processDataFields) {
final String dataFieldName = datafield.getName();
if (dataFieldNames.contains(dataFieldName)) {
problems.add(new Problem("Impossible to have more than one data with the name: " + dataFieldName,
Problem.SEVERITY_ERROR));
} else {
dataFieldNames.add(dataFieldName);
}
}
}
final Map attachments = definition.getAttachments();
if (attachments != null) {
for (final String attachmentName : attachments.keySet()) {
if (dataFieldNames.contains(attachmentName)) {
problems.add(new Problem("Impossible to have data and an attachment with the same name: " + attachmentName,
Problem.SEVERITY_ERROR));
}
}
}
final Set transitions = definition.getTransitions();
if (transitions != null) {
final List transitionNames = new ArrayList();
for (final TransitionDefinition transition : transitions) {
final String transitionName = transition.getName();
if (transitionNames.contains(transitionName)) {
problems.add(new Problem("Impossible to have more than one transition with the name: " + transitionName,
Problem.SEVERITY_ERROR));
} else {
transitionNames.add(transitionName);
}
}
}
final Set activities = definition.getActivities();
if (activities != null) {
final List activityNames = new ArrayList();
for (final ActivityDefinition activity : activities) {
final String activityName = activity.getName();
if (activityNames.contains(activityName)) {
problems.add(new Problem("Impossible to have more than one activity with the name: " + activityName,
Problem.SEVERITY_ERROR));
} else {
activityNames.add(activityName);
}
final Set activityDataFields = activity.getDataFields();
if (activityDataFields != null) {
final List activityDataNames = new ArrayList();
for (final DataFieldDefinition activityDataField : activityDataFields) {
final String activityDataName = activityDataField.getName();
if (activityDataNames.contains(activityDataName)) {
problems.add(new Problem("Impossible to have more than one data with name:" + activityDataName
+ " in the same activity", Problem.SEVERITY_ERROR));
} else {
activityDataNames.add(activityDataName);
}
}
}
final List events = activity.getBoundaryEvents();
for (final BoundaryEvent boundaryEvent : events) {
if (boundaryEvent.getTransition() == null) {
problems.add(new Problem("The boundary event " + boundaryEvent
+ " must have an outgoing transition in activity " + activityName + ".", Problem.SEVERITY_ERROR));
}
}
if (activity.isTerminateProcess() && !activity.getOutgoingTransitions().isEmpty()) {
problems.add(new Problem("The activity " + activityName
+ " cannot terminate a process with outgoing transitions", Problem.SEVERITY_ERROR));
}
if (activity.isSendEvents() && activity.getOutgoingEvents().isEmpty()) {
problems.add(new Problem("The send message event " + activityName + " must throw at least a message",
Problem.SEVERITY_ERROR));
}
}
}
}
private void checkTransientVariables() {
final ProcessDefinitionImpl definition = (ProcessDefinitionImpl) stack.get(0);
for (final DataFieldDefinition data : definition.getDataFields()) {
if (data.isTransient()) {
problems.add(new Problem("The process variable " + data.getName()
+ " cannot be setted as transient. Only activity variables can be transient.", Problem.SEVERITY_ERROR));
}
}
}
public static ProcessDefinition createProcessFromXmlDefFile(final URL xmlDefUrl, final Properties context) {
final Parse parse = new XmlDefParser().createParse();
parse.setContextProperties(context);
File file = null;
try {
final InputStream in = xmlDefUrl.openStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(in, BonitaConstants.FILE_ENCONDING));
String line = null;
file = Misc.createTempFile("tempProcessDef", ".xml", new File(BonitaConstants.getTemporaryFolder()));
final FileOutputStream fos = new FileOutputStream(file);
final OutputStream bos = new BufferedOutputStream(fos);
final OutputStreamWriter out = new OutputStreamWriter(bos, "UTF-8");
final String productVersionTag = "");
productVersion = line.substring(startIndex, lastIndex);
}
line = resolveWithContext(line, context);
out.write(line);
}
Misc.close(reader);
Misc.close(in);
Misc.close(out);
parse.setFile(file);
if (!XmlDefExporter.PRODUCT_VERSION.equals(productVersion)) {
final String message = "The given business archive was created with a different version of BOS. Please use the current BOS version ("
+ XmlDefExporter.PRODUCT_VERSION + ") to export your process";
file.delete();
Misc.showProblems(Collections.singleton(new Problem(message, Problem.SEVERITY_FATALERROR)), " your xml");
}
final ProcessDefinition process = (ProcessDefinition) parse.execute().getDocumentObject();
file.delete();
Misc.showProblems(parse.getProblems(), "xml file");
Misc.badStateIfNull(process, "Ouch! The returned Clientprocess is null!");
return process;
} catch (final IOException ex) {
throw new BonitaRuntimeException(ex);
}
}
static String resolveWithContext(final String value, final Properties context) {
if (!value.contains(BonitaConstants.CONTEXT_PREFIX)) {
return value;
} else {
final StringBuilder builder = new StringBuilder(value);
int startIndex = 0;
while ((startIndex = builder.indexOf(BonitaConstants.CONTEXT_PREFIX, startIndex)) != -1) {
final int closingIndex = builder.indexOf(BonitaConstants.CONTEXT_SUFFIX, startIndex);
final String key = builder.substring(startIndex + BonitaConstants.CONTEXT_PREFIX.length(), closingIndex);
if (context.containsKey(key)) {
builder.replace(startIndex, closingIndex + 1, context.get(key).toString());
}
startIndex++;
}
return builder.toString();
}
}
private boolean canAddBoundaryEvent(final ActivityDefinition activity, final String eventType) {
boolean can = false;
if (activity.isAutomatic() && "error".equals(eventType)) {
can = true;
}
if (activity.isSubflow() || activity.isTask() || activity.isReceiveEvent()) {
can = true;
}
return can;
}
}