org.jbpm.sim.jpdl.SimulationJpdlXmlReader Maven / Gradle / Ivy
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