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

org.jbpm.sim.jpdl.SimulationJpdlXmlReader Maven / Gradle / Ivy

There is a newer version: 3.2.19.ayg
Show newest version
package org.jbpm.sim.jpdl;

import java.io.Reader;
import java.io.StringReader;
import java.util.Iterator;

import org.dom4j.Element;
import org.xml.sax.InputSource;

import org.jbpm.graph.def.Event;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.NodeCollection;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.def.Transition;
import org.jbpm.graph.node.State;
import org.jbpm.graph.node.TaskNode;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.jbpm.jpdl.xml.ProblemListener;
import org.jbpm.sim.action.ProcessEndAction;
import org.jbpm.sim.action.ProcessStartAction;
import org.jbpm.sim.action.StartTaskAndPlanCompletion;
import org.jbpm.sim.def.DistributionDefinition;
import org.jbpm.sim.exe.ExperimentReader;
import org.jbpm.taskmgmt.def.Task;
import org.jbpm.taskmgmt.def.TaskMgmtDefinition;

/**
 * The SimulationJpdXmlReader is used instead of the original 
 * org.jbpm.jpdl.xml.JpdlXmlReader
 * from jBPM when using jBPM as simulation engine.
 * 
 * This reader instruments the process with additional things needed for simulation
 * 
 * @author [email protected]
 */
public class SimulationJpdlXmlReader extends JpdlXmlReader {

  
  public SimulationJpdlXmlReader(String processXml) {
    this(new InputSource(new StringReader(processXml)));    
  }
  
  public SimulationJpdlXmlReader(InputSource inputSource) {
    this(inputSource, null);
  }

  public SimulationJpdlXmlReader(Reader reader) {
    this(new InputSource(reader));
  }

  public SimulationJpdlXmlReader(InputSource inputSource, ProblemListener problemListener) {
    super(inputSource, problemListener);
  }

  public ProcessDefinition readProcessDefinition() {
    ProcessDefinition result = super.readProcessDefinition();
    instrument();
    return result;
  }
  
  /**
   * @return SimulationDefinition of process definition which is currently build.
   *         it is constructed on the fly, if it is not available
   */
  private SimulationDefinition getSimulationDefinition() {
    SimulationDefinition simulationDefinition = (SimulationDefinition) processDefinition.getDefinition(SimulationDefinition.class);
    if (simulationDefinition==null) {
      simulationDefinition = new SimulationDefinition();
      processDefinition.addDefinition(simulationDefinition);      
    }
    return simulationDefinition;
  }
  
  /**
   *  during instrumentation, you can:
   *  1) extract extra simulation information from the process xml and 
   *     store it in the simulation definition
   *  2) add event listeners to the process elements in processDefinition
   *  3) modify the whole processDefinition as you want
   */
  public void instrument() {    
    Element rootElement = super.document.getRootElement();
    SimulationDefinition simulationDefinition = getSimulationDefinition();
    
    /*
     * read information of resource pools
     */
    Iterator poolElementIter = rootElement.elementIterator("resource-pool");
    while (poolElementIter.hasNext()) {
      Element resourcePoolElement = (Element) poolElementIter.next();

      String poolName = resourcePoolElement.attributeValue("name");
      String poolSizeText = resourcePoolElement.attributeValue("pool-size");
      Integer poolSize = new Integer(poolSizeText);
      Double costPerTimeUnit = readCostPerTimeUnit(resourcePoolElement);
      
      simulationDefinition.addResourcePool(poolName, poolSize, costPerTimeUnit);
    }

    /*
     * swimlanes can serve as resource pools
     */
    Iterator swimlaneElementIter = rootElement.elementIterator("swimlane");
    while (swimlaneElementIter.hasNext()) {
      Element swimlaneElement = (Element) swimlaneElementIter.next();
      if (swimlaneElement.attributeValue("pool-size")!=null) {
        String poolName = swimlaneElement.attributeValue("name");
        String poolSizeText = swimlaneElement.attributeValue("pool-size");
        Integer poolSize = new Integer(poolSizeText);
        Double costPerTimeUnit = readCostPerTimeUnit(swimlaneElement);

        simulationDefinition.addResourcePool(poolName, poolSize, costPerTimeUnit);
      }
    }
    
    /*
     * read information of distributions
     */
    Iterator distributionIterator = rootElement.elementIterator("distribution");
    while (distributionIterator.hasNext()) {
      Element distributionElement = (Element) distributionIterator.next();
      DistributionDefinition distDef = ExperimentReader.readDistribution(distributionElement);      
      simulationDefinition.addDistribution(distDef);
    }
    
    /*
     * Events
     */
    // listen to all task assign events
    Event taskAssignEvent = new Event(Event.EVENTTYPE_TASK_CREATE);
    processDefinition.addEvent(taskAssignEvent);
    taskAssignEvent.addAction(new StartTaskAndPlanCompletion());

    // listen to all process start events to record count
    Event processStartEvent = new Event(Event.EVENTTYPE_BEFORE_SIGNAL);    
    processDefinition.getStartState().addEvent(processStartEvent);
    processStartEvent.addAction(new ProcessStartAction());

    // listen to all process end events to record cycle times of the process
    Event processEndEvent = new Event(Event.EVENTTYPE_PROCESS_END);    
    processDefinition.addEvent(processEndEvent);
    processEndEvent.addAction(new ProcessEndAction());
    
    
    /*
     * distribution usages
     */
    // process start distribution
    simulationDefinition.setStartDistribution( rootElement.attributeValue("start-distribution") );   
  }

  private Double readCostPerTimeUnit(Element resourcePoolElement) {
    String costPerTimeUnitText = resourcePoolElement.attributeValue("costs-per-time-unit");
    if (costPerTimeUnitText!=null)
      return Double.valueOf(costPerTimeUnitText);
    else
      return new Double(0);
  }

  public Task readTask(Element taskElement, TaskMgmtDefinition taskMgmtDefinition, TaskNode taskNode) {
    Task task = super.readTask(taskElement, taskMgmtDefinition, taskNode);
    
    // read distribution for task
    String distributionName = taskElement.attributeValue("time-distribution");
    getSimulationDefinition().addTaskDistribution(task, distributionName);
    
    // ONE resource from the pool named like the swimlane is always needed, if a swimlane is configured
    if (task.getSwimlane()!=null)
      getSimulationDefinition().addResourceRequirement(task, task.getSwimlane().getName(), 1);

    // read additional resource requirements
    readResourceUsages(taskElement, task);
    
    return task;
  }

  public void readNode(Element nodeElement, Node node, NodeCollection nodeCollection) {
    super.readNode(nodeElement, node, nodeCollection);

    // only instrument states
    if (State.class.isAssignableFrom(node.getClass())) {      
      String distributionName = nodeElement.attributeValue("time-distribution");
      getSimulationDefinition().addStateDistribution(node, distributionName);

      readResourceUsages(nodeElement, node);
    }
    // TODO: Later implement a resource requirement for whole TaskNode
    //       valid for all Tasks in it (but consumed only one for all Tasks
    //    else if (TaskNode.class.isAssignableFrom(node.getClass())) {    
    //       readResourceUsages(nodeElement, node);
    //     }
  }

  private void readResourceUsages(Element xmlElement, Object processElement) {
    Iterator iter = xmlElement.elementIterator("resource-needed");
    while (iter.hasNext()) {
      Element resourceElement = (Element) iter.next();
      String poolName = resourceElement.attributeValue("pool");
      String amountText = resourceElement.attributeValue("amount");

      int amount = 1;
      if (amountText!=null)
        amount = Integer.parseInt(amountText);
      
      getSimulationDefinition().addResourceRequirement(processElement, poolName, amount);
    }
  }

  public Transition resolveTransitionDestination(Element transitionElement, Node node) {
    Transition trans = super.resolveTransitionDestination(transitionElement, node);
    
    // read probabilities for outgoing transitions 
    String probString = transitionElement.attributeValue( "probability" );
    if (probString!=null) {
      double prob = Double.parseDouble(probString);
      getSimulationDefinition().addTransitionProbability(trans, prob);
    }
    
    return trans;
  }
  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy