All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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