
org.ow2.bonita.deployment.XpdlProcessBuilder Maven / Gradle / Ivy
/**
* Copyright (C) 2006 Bull S. A. S.
* Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois
* 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.deployment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ow2.bonita.pvm.activity.ExternalActivity;
import org.ow2.bonita.pvm.internal.model.CompositeElementImpl;
import org.ow2.bonita.pvm.internal.model.NodeImpl;
import org.ow2.bonita.pvm.internal.model.TimerDefinitionImpl;
import org.ow2.bonita.pvm.internal.model.TransitionImpl;
import org.ow2.bonita.pvm.internal.model.VariableDefinitionImpl;
import org.ow2.bonita.pvm.internal.wire.Descriptor;
import org.ow2.bonita.pvm.internal.wire.descriptor.ArgDescriptor;
import org.ow2.bonita.pvm.internal.wire.descriptor.BooleanHelper;
import org.ow2.bonita.pvm.internal.wire.descriptor.DoubleDescriptor;
import org.ow2.bonita.pvm.internal.wire.descriptor.LongDescriptor;
import org.ow2.bonita.pvm.internal.wire.descriptor.NullDescriptor;
import org.ow2.bonita.pvm.internal.wire.descriptor.ObjectDescriptor;
import org.ow2.bonita.pvm.internal.wire.descriptor.ProvidedObjectDescriptor;
import org.ow2.bonita.pvm.internal.wire.descriptor.SetDescriptor;
import org.ow2.bonita.pvm.internal.wire.descriptor.StringDescriptor;
import org.ow2.bonita.pvm.model.Condition;
import org.ow2.bonita.pvm.model.Node;
import org.ow2.bonita.pvm.model.Transition;
import org.ow2.bonita.definition.ClassInfo;
import org.ow2.bonita.definition.JavaHook;
import org.ow2.bonita.definition.Performer;
import org.ow2.bonita.definition.ProcessParameter;
import org.ow2.bonita.definition.XpdlProcess;
import org.ow2.bonita.definition.activity.AbstractActivity;
import org.ow2.bonita.definition.activity.ConditionDefinition;
import org.ow2.bonita.definition.activity.EndingNodeBehaviour;
import org.ow2.bonita.definition.activity.InitialNodeBehaviour;
import org.ow2.bonita.definition.activity.NoImplementation;
import org.ow2.bonita.definition.activity.Route;
import org.ow2.bonita.definition.activity.SubFlow;
import org.ow2.bonita.facade.def.dataType.BasicTypeDefinition;
import org.ow2.bonita.facade.def.dataType.DataTypeDefinition;
import org.ow2.bonita.facade.def.dataType.EnumerationTypeDefinition;
import org.ow2.bonita.facade.def.element.DeadlineDefinition;
import org.ow2.bonita.facade.def.element.FormalParameterDefinition;
import org.ow2.bonita.facade.def.element.HookDefinition;
import org.ow2.bonita.facade.def.element.MultiInstantiationDefinition;
import org.ow2.bonita.facade.def.element.SubFlowDefinition;
import org.ow2.bonita.facade.def.element.TransitionRestrictionDefinition;
import org.ow2.bonita.facade.def.element.TransitionRestrictionDefinition.JoinType;
import org.ow2.bonita.facade.def.majorElement.ActivityDefinition;
import org.ow2.bonita.facade.def.majorElement.ActivitySetDefinition;
import org.ow2.bonita.facade.def.majorElement.DataFieldDefinition;
import org.ow2.bonita.facade.def.majorElement.PackageFullDefinition;
import org.ow2.bonita.facade.def.majorElement.ParticipantDefinition;
import org.ow2.bonita.facade.def.majorElement.ProcessFullDefinition;
import org.ow2.bonita.facade.def.majorElement.TransitionDefinition;
import org.ow2.bonita.facade.runtime.var.Enumeration;
import org.ow2.bonita.parsing.XpdlParserException;
import org.ow2.bonita.util.DateUtil;
import org.ow2.bonita.util.EngineEnvTool;
/**
*
* @author Marc Blachon, Guillaume Porcher, Charles Souillard, Miguel Valdes, Pierre Vigneras
*/
public final class XpdlProcessBuilder {
private static final Logger LOG = Logger.getLogger(XpdlProcessBuilder.class.getName());
public static final String BONITA_INIT = "BonitaInit";
public static final String BONITA_END = "BonitaEnd";
private XpdlProcessBuilder() { }
public static XpdlProcess createXpdlProcess(final PackageFullDefinition packageDef,
final ProcessFullDefinition processDef) {
final XpdlProcess xpdlProcess = new XpdlProcess(processDef.getUUID(), packageDef.getPackageDefinitionUUID(),
createProcessParameters(processDef));
createNodes(packageDef, processDef, xpdlProcess);
initializeProcessVariables(packageDef, processDef, xpdlProcess);
IterationDetection.findIterations(xpdlProcess);
return xpdlProcess;
}
protected static List createProcessParameters(final ProcessFullDefinition processDef) {
final List formalParameters = processDef.getFormalParameters();
final List processParameters = new ArrayList();
if (formalParameters == null || formalParameters.isEmpty()) {
// Bonita 3 behaviour for subflow process
// TODO: this is deprecated and needs to be removed
if (processDef.getDataFields() != null) {
for (final DataFieldDefinition datafield : processDef.getDataFields()) {
if (!datafield.isActivityDataField()) {
processParameters.add(new ProcessParameter(ProcessParameter.ParameterType.INOUT, datafield.getDataFieldId()));
}
}
}
return processParameters;
}
for (final FormalParameterDefinition formalParameterDefinition : formalParameters) {
final String parameterName = formalParameterDefinition.getId();
ProcessParameter.ParameterType parameterType;
if (formalParameterDefinition.getMode().equals(FormalParameterDefinition.Mode.INOUT)) {
parameterType = ProcessParameter.ParameterType.INOUT;
} else if (formalParameterDefinition.getMode().equals(FormalParameterDefinition.Mode.OUT)) {
parameterType = ProcessParameter.ParameterType.OUT;
} else {
parameterType = ProcessParameter.ParameterType.IN;
}
processParameters.add(new ProcessParameter(parameterType, parameterName));
}
return processParameters;
}
protected static void createNodes(final PackageFullDefinition packageDef,
final ProcessFullDefinition processDef, final XpdlProcess xpdlProcess) {
final Set activities = getAllActivities(processDef);
//map of created activities : key = activity.id and value = corresponding node
final Map createdNodes = new HashMap();
for (final ActivityDefinition activity : activities) {
final NodeImpl node = createNode(activity, processDef, xpdlProcess, packageDef);
createdNodes.put(activity.getActivityId(), node);
}
createTransitions(processDef, createdNodes, packageDef.getScriptType());
// INITIAL / ENDING node creation
String initialEndCreationError = null;
//create initial split
NodeImpl initialNode = null;
if (createdNodes.containsKey(BONITA_INIT)) {
initialNode = createdNodes.get(BONITA_INIT);
} else {
initialNode = xpdlProcess.createNode(BONITA_INIT);
final Set initialActivities = getInitialActivities(processDef, activities);
if (!initialActivities.isEmpty()) {
//normal case, this process has at least one activity
//create a node for each initialActivity and create a transition from initialNode to initialActivities
for (final ActivityDefinition initialActivity : initialActivities) {
final NodeImpl initialActivityNode = createdNodes.get(initialActivity.getActivityId());
initialNode.createOutgoingTransition(initialActivityNode, "initialSplit_"
+ initialNode.getName() + "_to_" + initialActivityNode.getName());
}
} else {
if (!createdNodes.isEmpty()) {
//there is a problem, there are activities, but none of them are initial activities
//maybe a cycle ?
initialEndCreationError = "no initial";
}
}
}
final ExternalActivity initialRoute = new InitialNodeBehaviour();
initialNode.setBehaviour(initialRoute);
initialNode.setPreviousNeeded(true);
xpdlProcess.setInitial(initialNode);
//create ending join
NodeImpl endingNode = null;
if (createdNodes.containsKey(BONITA_END)) {
endingNode = createdNodes.get(BONITA_END);
} else {
endingNode = xpdlProcess.createNode(BONITA_END);
final Set endingActivities = getEndingActivities(processDef, activities);
if (!endingActivities.isEmpty()) {
//normal case, this process has at least one activity
//create node for each endingActivity and create a transition from ending activities to endingNode
for (final ActivityDefinition endingActivity : endingActivities) {
final NodeImpl endingActivityNode = createdNodes.get(endingActivity.getActivityId());
endingActivityNode.createOutgoingTransition(endingNode, "endingJoin_"
+ endingActivityNode.getName() + "_to_" + endingNode.getName());
}
} else {
if (!createdNodes.isEmpty()) {
//there is a problem, there are activities, but none of them are ending activities
//maybe a cycle ?
if (initialEndCreationError != null) {
initialEndCreationError += " and no ending";
} else {
initialEndCreationError = "no ending";
}
throw new DeploymentRuntimeException("Error in process definition: " + initialEndCreationError
+ " node found. There is maybe a cycle in activities definition");
}
//empty process (no activity)
initialNode.createOutgoingTransition(endingNode, "initialSplit_" + initialNode.getName() + "_to_" + endingNode.getName());
}
}
if (initialEndCreationError != null) {
throw new DeploymentRuntimeException("Error in process definition: " + initialEndCreationError
+ " node found. There is maybe a cycle in activities definition");
}
final ExternalActivity endingRoute = new EndingNodeBehaviour();
endingNode.setPreviousNeeded(true);
endingNode.setBehaviour(endingRoute);
// Add bonita 3 iterations
// (not real transitions, so added AFTER initial and ending nodes are checked)
createIterations(activities, xpdlProcess, packageDef.getScriptType());
// Check path from init to end
final Set activityNames = new HashSet();
activityNames.add(BONITA_END);
for (final ActivityDefinition act : activities) {
activityNames.add(act.getActivityId());
}
activityNames.remove(BONITA_INIT);
if (!checkReachable(activityNames, initialNode)) {
throw new DeploymentRuntimeException("There is no path from " + BONITA_INIT + " to " + BONITA_END);
}
if (!activityNames.isEmpty()) {
throw new DeploymentRuntimeException("These activities " + activityNames + " cannot be executed."
+ " There is no path from " + BONITA_INIT + " to them.");
}
}
private static boolean checkReachable(final Set nodeNames, final Node currentNode) {
boolean endReached = currentNode.getName().equals(BONITA_END);
final List trs = currentNode.getOutgoingTransitions();
if (trs != null) {
for (final Transition t : trs) {
if (nodeNames.remove(t.getDestination().getName())) {
endReached = checkReachable(nodeNames, t.getDestination()) || endReached;
}
}
}
return endReached;
}
/**
* @param activities
* @param xpdlProcess
*/
private static void createIterations(final Set activities,
final XpdlProcess xpdlProcess, final String packageScriptType) {
for (final ActivityDefinition activity : activities) {
if (activity.getIterations() != null) {
final NodeImpl fromNode = xpdlProcess.getNode(activity.getActivityId());
for (final ActivityDefinition.IterationDef iteration : activity.getIterations()) {
final NodeImpl destNode = xpdlProcess.getNode(iteration.getTo());
if (destNode == null) {
throw new DeploymentRuntimeException("iteration points to an unknown node: "
+ "cannot find a node with id '" + iteration.getTo() + "'");
}
final AbstractActivity destNodeActivity = (AbstractActivity) destNode.getBehaviour();
if (!destNodeActivity.getJoinType().equals(org.ow2.bonita.definition.activity.AbstractActivity.JoinType.XOR)) {
throw new DeploymentRuntimeException("iteration points to a node with a join "
+ destNodeActivity.getJoinType() + ", but only XOR are supported.");
}
final String transitionName = fromNode.getName() + "_" + destNode.getName();
final TransitionImpl transition = fromNode.createOutgoingTransition(destNode, transitionName);
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("**** created iteration transition = " + transitionName);
}
// check/set if condition on the transition
if (iteration.getCondition() != null) {
final Condition guardCondition = new ConditionDefinition(iteration.getCondition(), packageScriptType);
transition.setConditionDescriptor(new ProvidedObjectDescriptor(guardCondition));
}
}
}
}
}
protected static void createTransitions(final ProcessFullDefinition processDef,
final Map createdNodes, final String packageScriptType) {
final Set transitions = processDef.getTransitions();
if (transitions != null) {
for (final TransitionDefinition transition : transitions) {
final String toActivityId = transition.getTo();
final String fromActivityId = transition.getFrom();
String condition = null;
if (transition.getCondition() != null) {
condition = transition.getCondition().getContentAsString();
}
if (!activityWithIdExist(processDef, toActivityId)) {
throw new DeploymentRuntimeException("Transition " + transition.getTransitionId() + " is using activity "
+ toActivityId + " in to attribute. There is no activity with this uuid in the defined workflowprocess.");
}
if (!activityWithIdExist(processDef, fromActivityId)) {
throw new DeploymentRuntimeException("Transition " + transition.getTransitionId() + " is using activity "
+ fromActivityId + " in from attribute. There is no activity with this uuid in the defined workflowprocess.");
}
final NodeImpl fromNode = createdNodes.get(fromActivityId);
final NodeImpl toNode = createdNodes.get(toActivityId);
final String transitionName = fromActivityId + "_" + toActivityId;
final TransitionImpl pvmTransition = fromNode.createOutgoingTransition(toNode, transitionName);
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("**** created transition = " + transitionName);
}
// check/set if condition on the transition
if (condition != null) {
final Condition guardCondition = new ConditionDefinition(condition, packageScriptType);
pvmTransition.setConditionDescriptor(new ProvidedObjectDescriptor(guardCondition));
}
}
}
}
protected static NodeImpl createNode(final ActivityDefinition activity, final ProcessFullDefinition processDef,
final XpdlProcess xpdlProcess, final PackageFullDefinition packageDef) {
final NodeImpl node = xpdlProcess.createNode(activity.getActivityId());
if (activity.isAsynchronous()) {
node.setExecutionAsync(true);
}
AbstractActivity abstractActivity = null;
final org.ow2.bonita.definition.activity.AbstractActivity.JoinType joinType =
getJoinFromActivity(activity, getIncomingTransitionNb(processDef, activity.getActivityId()));
final org.ow2.bonita.definition.activity.AbstractActivity.SplitType splitType =
getSplitFromActivity(activity, getOutgoingTransitionNb(processDef, activity.getActivityId()));
Performer performer = null;
createVariableDefinitionsFromDataFields(node, activity.getDataFields(),
getParticipantIds(packageDef, processDef));
if (activity.getStartMode().equals(ActivityDefinition.StartMode.Automatic)) {
if (activity.getPerformer() != null) {
final ParticipantDefinition participant = findParticipant(packageDef, processDef, activity.getPerformer());
if (participant.getParticipantType().equals(ParticipantDefinition.ParticipantType.HUMAN)
|| participant.getParticipantType().equals(ParticipantDefinition.ParticipantType.ROLE)
|| participant.getParticipantType().equals(ParticipantDefinition.ParticipantType.ORGANIZATIONAL_UNIT)) {
throw new DeploymentRuntimeException("A performer(HUMAN, ROLE or ORGANIZATIONAL_UNIT) is defined on activity : "
+ activity.getActivityId() + " but StartMode and FinishMode are AUTOMATIC...");
}
}
} else {
performer = getPerformer(activity, processDef, packageDef);
if (!activity.isNoImplementation()) {
throw new DeploymentRuntimeException("Only NoImplementation "
+ "activities are supported with a manual StartMode or FinishMode");
}
}
if (activity.isNoImplementation()) {
final boolean isTask = activity.getStartMode().equals(ActivityDefinition.StartMode.Manual);
abstractActivity = new NoImplementation(activity.getActivityId(), joinType,
splitType,
performer,
isTask
);
} else if (activity.getTools() != null && !activity.getTools().isEmpty()) {
throw new DeploymentRuntimeException("Tool Implementation not supported in activity");
} else if (activity.getSubFlow() != null && activity.getSubFlow().getProcessId() != null) {
final SubFlowDefinition subFlow = activity.getSubFlow();
final String subProcessId = subFlow.getProcessId();
List processParameters = null;
final ProcessFullDefinition subProcess = getProcess(packageDef.getProcesses(), subProcessId);
if (subProcess != null) {
processParameters = createProcessParameters(subProcess);
} else {
final XpdlProcess externalSubProcess = EngineEnvTool.getRepository().findLatestProcessById(subProcessId);
if (externalSubProcess == null) {
throw new DeploymentRuntimeException("Unable to find process \"" + subProcessId + "\" used in subFlow. "
+ "If the subFlow process is in an external package, "
+ "please check that this package has already been deployed");
}
processParameters = externalSubProcess.getParameters();
}
final Map inParameters = new HashMap();
final Map outParameters = new HashMap();
if (subFlow.getActualParameters() != null) {
final Iterator parameters = subFlow.getActualParameters().iterator();
if (subFlow.getActualParameters().size() != processParameters.size()) {
throw new DeploymentRuntimeException("Invalid number of parameters in subFlow : " + subProcessId);
}
for (final ProcessParameter processParameter : processParameters) {
final String variableId = parameters.next();
if (processParameter.getType().equals(ProcessParameter.ParameterType.IN)
|| processParameter.getType().equals(ProcessParameter.ParameterType.INOUT)) {
inParameters.put(processParameter.getName(), variableId);
}
if (processParameter.getType().equals(ProcessParameter.ParameterType.OUT)
|| processParameter.getType().equals(ProcessParameter.ParameterType.INOUT)) {
outParameters.put(processParameter.getName(), variableId);
}
}
} else {
//BONITA 3 behaviour
// TODO: remove this
if (node.getVariableDefinitions() != null && !node.getVariableDefinitions().isEmpty()) {
for (final VariableDefinitionImpl var : node.getVariableDefinitions()) {
inParameters.put(var.getKey(), var.getKey());
}
}
for (final ProcessParameter processParameter : processParameters) {
outParameters.put(processParameter.getName(), processParameter.getName());
}
}
abstractActivity = new SubFlow(activity.getActivityId(), joinType, splitType,
performer, subProcessId,
subFlow.getExecution().equals(SubFlowDefinition.Execution.ASYNCHR),
inParameters, outParameters);
} else if (activity.isRoute()) {
if (node.getVariableDefinitions() != null && !node.getVariableDefinitions().isEmpty()) {
throw new DeploymentRuntimeException("A route activity can't define local variables.");
}
abstractActivity = new Route(activity.getActivityId(), joinType, splitType);
} else if (activity.getBlockId() != null) {
throw new DeploymentRuntimeException("BlockActivity Implementation not supported in activity");
} else {
throw new DeploymentRuntimeException("unknown ActivityType");
}
abstractActivity.setJavaHooks(getActivityHooks(activity));
abstractActivity.setDeadlineHooks(createTimerDefinitions(activity, node));
final MultiInstantiationDefinition multiInstantiationDefinition = activity.getMultiInstantiationDefinition();
if (multiInstantiationDefinition != null) {
final String variableId = multiInstantiationDefinition.getVariableId();
boolean variableExists = false;
if (node.getVariableDefinitions() != null) {
for (final VariableDefinitionImpl var : node.getVariableDefinitions()) {
if (var.getKey().equals(variableId)) {
variableExists = true;
break;
}
}
}
if (!variableExists) {
throw new DeploymentRuntimeException("MultiInstantiation variable " + variableId
+ " must be a local variable of activity " + activity.getActivityId());
}
abstractActivity.setMultiInstantiation(
variableId,
new ClassInfo(
multiInstantiationDefinition.getClassName(),
multiInstantiationDefinition.getParameters())
);
}
node.setBehaviour(abstractActivity);
node.setPreviousNeeded(true);
return node;
}
protected static ProcessFullDefinition getProcess(final Set processes, final String processId) {
if (processes == null) {
return null;
}
for (final ProcessFullDefinition process : processes) {
if (process.getProcessId().equals(processId)) {
return process;
}
}
return null;
}
protected static List getActivityHooks(final ActivityDefinition activity) {
if (activity.getHooks() != null) {
final List javaHooks = new ArrayList();
for (final HookDefinition hook : activity.getHooks()) {
final boolean inTransaction = hook.isThrowingException();
final JavaHook.Type type = JavaHook.MAPPING.get(hook.getEvent());
final JavaHook javaHook = new JavaHook(hook.getClassName(), type, inTransaction);
javaHooks.add(javaHook);
}
return javaHooks;
}
return null;
}
protected static Set getAllActivities(final ProcessFullDefinition processDef) {
final Set activities = new HashSet();
final Set processActivities = processDef.getActivities();
if (processActivities != null) {
activities.addAll(processActivities);
}
final Set activitySets = processDef.getActivitySets();
if (activitySets != null) {
final Set activitySetsActivities = new HashSet();
for (final ActivitySetDefinition activitySet : activitySets) {
if (activitySet.getActivities() != null) {
activitySetsActivities.addAll(activitySet.getActivities());
}
}
if (!activitySetsActivities.isEmpty()) {
activities.addAll(activitySetsActivities);
}
}
return activities;
}
protected static Set getInitialActivities(final ProcessFullDefinition processDef,
final Set activitiesToAnalyse) {
final Set initialActivities = new HashSet();
for (final ActivityDefinition activity : activitiesToAnalyse) {
if (getIncomingTransitionNb(processDef, activity.getActivityId()) == 0) {
initialActivities.add(activity);
}
}
return initialActivities;
}
protected static Set getEndingActivities(final ProcessFullDefinition processDef,
final Set activitiesToAnalyse) {
final Set endingActivities = new HashSet();
for (final ActivityDefinition activity : activitiesToAnalyse) {
if (getOutgoingTransitionNb(processDef, activity.getActivityId()) == 0) {
endingActivities.add(activity);
}
}
return endingActivities;
}
protected static int getIncomingTransitionNb(final ProcessFullDefinition processDef, final String activityId) {
int incomingTransitionNb = 0;
if (processDef.getTransitions() != null) {
for (final TransitionDefinition transition : processDef.getTransitions()) {
if (transition.getTo().equals(activityId)) {
incomingTransitionNb++;
}
}
}
return incomingTransitionNb;
}
protected static int getOutgoingTransitionNb(final ProcessFullDefinition processDef, final String activityId) {
int outgoingTransitionNb = 0;
if (processDef.getTransitions() != null) {
for (final TransitionDefinition transition : processDef.getTransitions()) {
if (transition.getFrom().equals(activityId)) {
outgoingTransitionNb++;
}
}
}
return outgoingTransitionNb;
}
protected static AbstractActivity.JoinType getJoinFromActivity(
final ActivityDefinition activity, final int incomingTransitions) {
AbstractActivity.JoinType joinType = null;
if (activity.getTransitionRestrictions() != null) {
for (final TransitionRestrictionDefinition transitionRestriction : activity.getTransitionRestrictions()) {
if (transitionRestriction.getJoinType() != null) {
if (joinType != null) {
if (LOG.isLoggable(Level.WARNING)) {
LOG.warning("Found more than one join inside activity: " + activity + ". Using first found: " + joinType);
}
} else {
if (transitionRestriction.getJoinType().equals(JoinType.XOR)) {
joinType = AbstractActivity.JoinType.XOR;
} else {
joinType = AbstractActivity.JoinType.AND;
}
}
}
}
}
if (joinType != null) {
return joinType;
}
if (LOG.isLoggable(Level.INFO)) {
LOG.info("No join type found for activity with " + incomingTransitions + " incoming transitionDestNode: "
+ activity.getActivityId() + ". Though this is allowed by XSD, it looks strange. Bonita supposes it is a Join/XOR");
}
return AbstractActivity.JoinType.XOR;
}
protected static AbstractActivity.SplitType getSplitFromActivity(
final ActivityDefinition activity, final int outgoingTransitionNb) {
org.ow2.bonita.facade.def.element.TransitionRestrictionDefinition.SplitType splitType = null;
if (activity.getTransitionRestrictions() != null) {
for (final TransitionRestrictionDefinition transitionRestriction : activity.getTransitionRestrictions()) {
if (transitionRestriction.getSplitType() != null) {
if (splitType != null) {
if (LOG.isLoggable(Level.WARNING)) {
LOG.warning("Found more than one split inside activity: " + activity + ". Using first found: " + splitType);
}
} else {
splitType = transitionRestriction.getSplitType();
}
}
}
}
if (splitType == null) {
if (outgoingTransitionNb > 1) {
if (LOG.isLoggable(Level.WARNING)) {
LOG.warning("No split type found for activity with " + outgoingTransitionNb + " outgoing transitionSourceNodes: "
+ activity.getActivityId() + ". Though this is allowed by XSD, it looks strange. Bonita supposes it is a Split/AND");
}
}
splitType = org.ow2.bonita.facade.def.element.TransitionRestrictionDefinition.SplitType.AND;
}
switch (splitType) {
case AND:
return AbstractActivity.SplitType.AND;
case XOR:
return AbstractActivity.SplitType.XOR;
default:
throw new DeploymentRuntimeException("Ouch! I Don't understand this Split Type: " + splitType);
}
}
protected static Performer getPerformer(final ActivityDefinition activity,
final ProcessFullDefinition processDef, final PackageFullDefinition packageDef) {
// get the participant definition from the performer
final ParticipantDefinition participant = findParticipant(packageDef, processDef, activity.getPerformer());
if (participant == null) {
throw new DeploymentRuntimeException("Wrong performer: " + activity.getPerformer()
+ ". No participant is defined within the package with processDefinitionUUID: " + activity.getPerformer());
}
ClassInfo roleMapper = null;
ClassInfo performerAssign = null;
if (participant.getRoleMapper() != null && participant.getRoleMapper().getClassName() != null) {
roleMapper = new ClassInfo(participant.getRoleMapper().getClassName(), participant.getRoleMapper().getParameters());
}
if (activity.getPerformerAssign() != null && activity.getPerformerAssign().getClassName() != null) {
performerAssign = new ClassInfo(activity.getPerformerAssign().getClassName(),
activity.getPerformerAssign().getParameters());
}
return new Performer(participant.getParticipantId(), participant.getParticipantType(),
participant.getUUID(), roleMapper, performerAssign);
}
protected static ParticipantDefinition findParticipant(final PackageFullDefinition packageDef,
final ProcessFullDefinition processDef, final String participantId) {
if (packageDef.getParticipants() != null) {
for (final ParticipantDefinition participant : packageDef.getParticipants()) {
if (participant.getParticipantId().equals(participantId)) {
return participant;
}
}
}
if (processDef.getParticipants() != null) {
for (final ParticipantDefinition participant : processDef.getParticipants()) {
if (participant.getParticipantId().equals(participantId)) {
return participant;
}
}
}
return null;
}
protected static void createVariableDefinitionsFromDataFields(final CompositeElementImpl element,
final Collection dataFields, final Set participantIds) {
if (dataFields != null && !dataFields.isEmpty()) {
for (final DataFieldDefinition dataField : dataFields) {
final VariableDefinitionImpl variable = element.createVariableDefinition();
variable.setKey(dataField.getDataFieldId());
variable.setSourceDescriptor(getInitialValueDescriptor(dataField, participantIds));
}
}
}
protected static void initializeProcessVariables(final PackageFullDefinition packageDef,
final ProcessFullDefinition processDef, final XpdlProcess xpdlProcess) {
// process variables are made of:
// workflow out parameters (initialized to null). See Xpdl spec 7.1.2.1.
// workflow variables
// and package inherited variables
final List formalParameters = processDef.getFormalParameters();
if (formalParameters != null) {
for (final FormalParameterDefinition formalParameter : formalParameters) {
// out params are initialized with a null value
// Xpdl 1.0 spec specifies in 7.1.2.1 that out parameters are initialized to zero
// (empty string for strings, zero for each component of complex data)
// It 's easier to set the variable to null, but maybe this needs to be changed.
if (formalParameter.getMode().equals(FormalParameterDefinition.Mode.OUT)) {
final VariableDefinitionImpl varDef = xpdlProcess.createVariableDefinition();
varDef.setKey(formalParameter.getId());
}
}
}
final Map dataFields = new HashMap();
if (processDef.getDataFields() != null) {
for (final DataFieldDefinition datafield : processDef.getDataFields()) {
dataFields.put(datafield.getDataFieldId(), datafield);
}
}
if (packageDef.getDataFields() != null) {
for (final DataFieldDefinition dataField : packageDef.getDataFields()) {
if (!dataFields.containsKey(dataField.getDataFieldId())) {
dataFields.put(dataField.getDataFieldId(), dataField);
}
}
}
createVariableDefinitionsFromDataFields(xpdlProcess, dataFields.values(),
getParticipantIds(packageDef, processDef));
}
/*
* This method is used to validate the initial value of PERFORMER dataFields.
* Another method would be to pass packageDef and processDef to method
* getPerformerInitialValueDescriptor and to look for the participant.
* The current behaviour is more efficient if there are several Performer dataFields
* (the cost of creating the set VS the gained time in reading the set)
* @return a set containing the IDs of the participants defined in the given
* package and process
* @author Pascal Verdage
*/
private static Set getParticipantIds(final PackageFullDefinition packageDef,
final ProcessFullDefinition processDef) {
final Set result = new HashSet();
if (packageDef != null && packageDef.getParticipants() != null) {
for (final ParticipantDefinition participantDef : packageDef.getParticipants()) {
result.add(participantDef.getParticipantId());
}
}
if (processDef != null && processDef.getParticipants() != null) {
for (final ParticipantDefinition participantDef : processDef.getParticipants()) {
result.add(participantDef.getParticipantId());
}
}
return result;
}
/**
* create a descriptor for the initial value of a BasicType BOOLEAN element
*/
private static Descriptor getBooleanInitialValueDescriptor(final String value) {
Boolean b = null;
if (value != null) {
b = Boolean.valueOf(value);
}
return BooleanHelper.createDescriptor(b);
}
/**
* create a descriptor for the initial value of a BasicType INTEGER element
*/
private static Descriptor getIntegerInitialValueDescriptor(final String value) {
Long i = null;
if (value != null) {
if (value.length() == 0) {
i = 0L;
} else {
i = Long.valueOf(value);
}
}
final LongDescriptor descriptor = new LongDescriptor();
descriptor.setValue(i);
return descriptor;
}
/**
* create a descriptor for the initial value of a BasicType FLOAT element
*/
private static Descriptor getFloatInitialValueDescriptor(final String value) {
Double flt = null;
if (value != null) {
if (value.length() == 0) {
flt = Double.valueOf(0);
} else {
flt = Double.valueOf(value);
}
}
final DoubleDescriptor descriptor = new DoubleDescriptor();
descriptor.setValue(flt);
return descriptor;
}
/**
* create a descriptor for the initial value of a BasicType DATETIME element
*/
private static Descriptor getDateTimeInitialValueDescriptor(final String value) {
if (value == null || value.length() == 0) {
return new NullDescriptor();
}
// we try to create the object a first time to be sure it is valid
try {
DateUtil.parseDate(value);
} catch (final IllegalArgumentException e) {
throw new XpdlParserException("invalid formatted date: " + value + ".", e);
}
// creation of the descriptor
final ObjectDescriptor descriptor = new ObjectDescriptor();
descriptor.setClassName(DateUtil.class.getName());
descriptor.setMethodName("parseDate");
final ArgDescriptor argDescriptor = new ArgDescriptor();
argDescriptor.setTypeName(String.class.getName());
argDescriptor.setDescriptor(new StringDescriptor(value));
descriptor.addArgDescriptor(argDescriptor);
return descriptor;
}
/**
* create a descriptor for the initial value of a BasicType PERFORMER element
* @throws XpdlParserException if the value is not an existing ParticipantId
*/
private static Descriptor getPerformerInitialValueDescriptor(final String value,
final Set participantIds, final String dataFieldName) {
Descriptor descriptor;
if (value == null || value.length() == 0) {
descriptor = new NullDescriptor();
} else {
if (participantIds != null && participantIds.contains(value)) {
descriptor = new StringDescriptor(value);
} else {
throw new XpdlParserException("Invalid value: Participant " + value
+ " does not exist in the naming context of datafield " + dataFieldName);
}
}
return descriptor;
}
/**
* create a descriptor for the initialValue of a dataField
* @param packageDef: the package definition; used for a PERFORMER dataField
* @param processDef: the process definition; used for a PERFORMER dataField
* @param dataField: the dataField definition
* @return a descriptor of the initial value
*/
protected static Descriptor getInitialValueDescriptor(final DataFieldDefinition dataField,
final Set participantIds) {
final DataTypeDefinition dataType = dataField.getDataType();
if (dataType.getType().equals(DataTypeDefinition.Type.BasicType)) {
final BasicTypeDefinition.Type type = ((BasicTypeDefinition) dataType.getValue().copy()).getType();
final String value = dataField.getInitialValue();
switch (type) {
case BOOLEAN:
return getBooleanInitialValueDescriptor(value);
case STRING:
return new StringDescriptor(value);
case INTEGER:
return getIntegerInitialValueDescriptor(value);
case FLOAT:
return getFloatInitialValueDescriptor(value);
case DATETIME:
return getDateTimeInitialValueDescriptor(value);
case PERFORMER:
return getPerformerInitialValueDescriptor(value, participantIds, dataField.getName());
case REFERENCE:
return null;
default:
throw new XpdlParserException("Unknow basic type: " + type);
}
} else if (dataType.getType().equals(DataTypeDefinition.Type.EnumerationType)) {
final ObjectDescriptor descriptor = new ObjectDescriptor();
descriptor.setClassName(Enumeration.class.getName());
final StringDescriptor initialValue = new StringDescriptor();
initialValue.setValue(dataField.getInitialValue());
final EnumerationTypeDefinition enumerationType = (EnumerationTypeDefinition) dataType.getValue().copy();
if (!enumerationType.getEnumerationValues().contains(dataField.getInitialValue())) {
throw new XpdlParserException(
"Invalid enumeration value: " + dataField.getInitialValue()
+ " is not in " + enumerationType.getEnumerationValues());
}
final SetDescriptor setValues = new SetDescriptor();
final List valueDescriptors = new ArrayList();
for (final String value : enumerationType.getEnumerationValues()) {
final StringDescriptor valueDescriptor = new StringDescriptor();
valueDescriptor.setValue(value);
valueDescriptors.add(valueDescriptor);
}
setValues.setValueDescriptors(valueDescriptors);
final ArgDescriptor listArg = new ArgDescriptor();
listArg.setDescriptor(setValues);
final ArgDescriptor selectArg = new ArgDescriptor();
selectArg.setDescriptor(initialValue);
descriptor.addArgDescriptor(listArg);
descriptor.addArgDescriptor(selectArg);
return descriptor;
}
return null;
}
protected static boolean activityWithIdExist(final ProcessFullDefinition process, final String activityId) {
final Set activities = process.getActivities();
if (activities != null) {
for (final ActivityDefinition activity : activities) {
if (activity.getActivityId().equals(activityId)) {
return true;
}
}
}
//scope of from and to is the surrounding scope (see spec p40)
return false;
}
protected static Set createTimerDefinitions(final ActivityDefinition activity, final NodeImpl node) {
if (activity.getDeadlines() != null) {
final Set deadlineHooks = new HashSet();
for (final DeadlineDefinition deadline : activity.getDeadlines()) {
deadlineHooks.add(deadline.getExceptionName());
createTimerDefinition(node, deadline);
}
return deadlineHooks;
}
return null;
}
protected static void createTimerDefinition(final NodeImpl node, final DeadlineDefinition deadline) {
final TimerDefinitionImpl timerDefinition = node.createTimerDefinition();
timerDefinition.setSignalName(deadline.getExceptionName());
final String condition = deadline.getDeadlineCondition();
try {
final long duration = Long.parseLong(condition);
timerDefinition.setDueDateDescription(duration + " millis");
} catch (final NumberFormatException e1) {
try {
timerDefinition.setDueDate(DateUtil.parseDate(condition));
} catch (final IllegalArgumentException e2) {
throw new XpdlParserException("deadline condition '" + deadline.getDeadlineCondition()
+ "' is neither a Long nor a formatted date", e2);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy