package org.jbpm.sim; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.jbpm.graph.def.ActionHandler; import org.jbpm.graph.def.ProcessDefinition; import org.jbpm.graph.exe.ExecutionContext; import org.jbpm.graph.exe.ProcessInstance; import org.jbpm.sim.def.DefaultJbpmSimulationModel; import org.jbpm.sim.jpdl.SimulationInstance; import org.jbpm.sim.jpdl.SimulationJpdlXmlReader; import org.jbpm.taskmgmt.exe.TaskInstance; import org.jbpm.taskmgmt.exe.TaskMgmtInstance; import desmoj.core.simulator.Experiment; import desmoj.core.simulator.SimTime; public class LanguageDefinitionTest extends AbstractSimTestCase { public void testDistributionsOnProcessElements() { Experiment exp = new Experiment(getName(), "target"); exp.setShowProgressBar(false); // distributions: type=real constant|empirical|erlang|exponential|normal|uniform // distributions: type=int constant|empirical|poison|uniform // distributions: type=boolean constant|bernoulli true-probability='0.3' value='true' // min='5' max='10' mean='7' value='10' // <type='empirical> // <sample value='10' frequency='0.3' /> String processXml = "<process-definition name='test' start-distribution='start new process instances of test'>" + " <distribution name='start new process instances of test' sample-type='real' type='constant' value='20' /> " + " <distribution name='time required for task one' sample-type='real' type='normal' mean='25' standardDeviation='10' /> " + " <distribution name='time required for task two' sample-type='real' type='normal' mean='6' standardDeviation='1' /> " + " <distribution name='time required for automated state' sample-type='real' type='normal' mean='6' standardDeviation='1' /> " + " <resource-pool name='tester' pool-size='2' />" + " <resource-pool name='big machine' pool-size='3' />" + // TODO: think about shifts for resource pools and implement // " <resource-pool name='big machine'>" + // " <shift from='xx' till='xx' pool-size='3' />" + // " </resource-pool>" + " <swimlane name='tester' pool-size='1' />" + " <start-state name='start'>" + " <transition to='task one' />" + " </start-state>" + " <task-node name='task one'>" + " <task swimlane='tester' time-distribution='time required for task one' />" + " <transition to='task two' />" + " </task-node>" + " <task-node name='task two'>" + " <task swimlane='tester' time-distribution='time required for task two' />" + " <transition to='automated state' />" + " </task-node>" + " <state name='automated state' time-distribution='time required for automated state'>" + " <resource-needed pool='big machine' amount='2' />" + " <transition to='end' />" + " </state>" + " <end-state name='end'/>" + "</process-definition>" ; // make a new model with the given process DefaultJbpmSimulationModel model = new DefaultJbpmSimulationModel(processXml); // connect Experiment and Model model.connectToExperiment(exp); // now set the time this simulation should stop at // exp.stop(new SimTime(7500)); exp.stop(new SimTime(10)); //exp.setShowProgressBar(false); // start the Experiment with start time 0.0 exp.start(); // --> now the simulation is running until it reaches its ending criteria // ... // ... // <-- after reaching ending criteria, the main thread returns here // print the report about the already existing reporters into the report file exp.report(); // stop all threads still alive and close all output files exp.finish(); } /** * static list to remember executed actions. * Not the nice way, but I don't get a better idea at the moment */ public static List executedActions; public static class TestAction implements ActionHandler { private boolean shouldBeExecuted; private static final long serialVersionUID = 1L; public void execute(ExecutionContext executionContext) throws Exception { if (!shouldBeExecuted) throw new RuntimeException("action '"+executionContext.getAction().getName()+"' should not be executed in a simulation run."); executedActions.add(executionContext.getAction()); } } public static class SimTestAction implements ActionHandler { private static final long serialVersionUID = 1L; public void execute(ExecutionContext executionContext) throws Exception { executedActions.add(executionContext.getAction()); } } /** * tests the action configuration for the simulation. Valid values: * <action name="xy" class="x.y" simulation=execute|skip /> * <action name="xy" class="x.y" simulation-class="sim.x' /> * <simulation-action name="xy" class="sim.x" /> */ public void testAction() { String processXml = "<process-definition name='test'>" + " <start-state name='start'>" + " <transition to='node one' />" + " </start-state>" + " <node name='node one'>" + " <transition to='node two'>" + " <action name ='action 1' class='org.jbpm.sim.LanguageDefinitionTest$TestAction'>" + " <shouldBeExecuted>false</shouldBeExecuted>" + " </action>" + " <action name ='action 2' class='org.jbpm.sim.LanguageDefinitionTest$TestAction' simulation='skip'>" + " <shouldBeExecuted>false</shouldBeExecuted>" + " </action>" + " <action name ='action 3' class='org.jbpm.sim.LanguageDefinitionTest$TestAction' simulation='execute'>" + " <shouldBeExecuted>true</shouldBeExecuted>" + " </action>" + " </transition>" + " </node>" + " <node name='node two'>" + " <transition to='end'>" + " <action name ='sim-action 1' class='org.jbpm.sim.LanguageDefinitionTest$TestAction' simulation-class='org.jbpm.sim.LanguageDefinitionTest$SimTestAction'>" + " <shouldBeExecuted>false</shouldBeExecuted>" + " </action>" + " <simulation-action name ='sim-action 2' class='org.jbpm.sim.LanguageDefinitionTest$SimTestAction'>" + " </simulation-action>" + " </transition>" + " </node>" + " <end-state name='end'/>" + "</process-definition>" ; SimulationJpdlXmlReader reader = new SimulationJpdlXmlReader(processXml); ProcessDefinition pd = reader.readProcessDefinition(); // remember executed actions executedActions = new ArrayList(); ProcessInstance processInstance = pd.createProcessInstance(); processInstance.signal(); // now check, if the right actions have been executed assertTrue(processInstance.hasEnded()); assertEquals(3, executedActions.size()); assertTrue(executedActions.contains( pd.getAction("action 3") )); assertTrue(executedActions.contains( pd.getAction("sim-action 1") )); assertTrue(executedActions.contains( pd.getAction("sim-action 2") )); } public void testScript() { String processXml = "<process-definition name='test'>" + " <start-state name='start'>" + " <transition to='node one' />" + " </start-state>" + " <node name='node one'>" + " <transition to='node two'>" + " <script name ='not executed in sim 1'>" + " <expression>executed.add(\"script 1\");</expression>" + " </script>" + " <script name ='not executed in sim 2' simulation='skip'>" + " <expression>executed.add(\"script 2\");</expression>" + " </script>" + " <script name ='executed in sim 2' simulation='execute'>" + " <expression>executed.add(\"script 3\");</expression>" + " </script>" + " </transition>" + " </node>" + " <node name='node two'>" + " <transition to='end'>" + " <script name ='simulation script 1'>" + " <expression>executed.add(\"script 4\");</expression>" + " <simulation-expression>executed.add(\"sim-script 1\");</simulation-expression>" + " </script>" + " <simulation-script name ='simulation script 2'>" + " <expression>executed.add(\"sim-script 2\");</expression>" + " </simulation-script>" + " </transition>" + " </node>" + " <end-state name='end'/>" + "</process-definition>" ; SimulationJpdlXmlReader reader = new SimulationJpdlXmlReader(processXml); ProcessDefinition pd = reader.readProcessDefinition(); ProcessInstance processInstance = pd.createProcessInstance(); processInstance.getContextInstance().setVariable("executed", new ArrayList()); processInstance.signal(); // now check, if the right actions have been executed ArrayList executedActions = (ArrayList) processInstance.getContextInstance().getVariable("executed"); assertTrue(processInstance.hasEnded()); assertTrue(executedActions.contains( "script 3") ); assertTrue(executedActions.contains( "sim-script 2") ); assertTrue(executedActions.contains( "sim-script 1") ); assertEquals(3, executedActions.size()); } public void testLeavingTransitionProbabilities() { String processXml = "<process-definition name='test'>" + " <distribution name='no work' sample-type='real' type='constant' value='1' /> " + " <start-state name='start'>" + " <transition to='node one' />" + " </start-state>" + " <task-node name='node one' >" + " <task name='task one' time-distribution='no work' />" + " <transition name='t2' to='end' probability='0.0'/>" + " <transition name='t1' to='node two' probability='1.0'/>" + " </task-node>" + " <state name='node two' time-distribution='no work'>" + " <transition name='t3' to='end' probability='1.0'/>" + " <transition name='t4' to='end' probability='1.0'/>" + " <transition name='t5' to='end' probability='1.0'/>" + " </state>" + " <end-state name='end'/>" + "</process-definition>" ; Experiment exp = new Experiment(getName(), "target"); exp.setShowProgressBar(false); // make a new model with the given process DefaultJbpmSimulationModel model = new DefaultJbpmSimulationModel(processXml); // connect Experiment and Model model.connectToExperiment(exp); // start a process instance, which generates events ProcessInstance processInstance = new ProcessInstance(model.getProcessDefinitions()[0]); SimulationInstance simulationInstance = (SimulationInstance)processInstance.getInstance(SimulationInstance.class); simulationInstance.setExperiment(model); processInstance.signal(); exp.stop(new SimTime(3)); exp.setShowProgressBar(false); exp.start(); exp.report(); exp.finish(); // now check which transitions were taken // TODO: implement check which transitions were taken } public void testDecisionProbability() { String processXml = "<process-definition name='test'>" + " <distribution name='no work' sample-type='real' type='constant' value='1' /> " + " <start-state name='start'>" + " <transition to='unaffected decision' />" + " </start-state>" + " <decision name='unaffected decision' expression='valid'>" + " <transition name='invalid' to='end invalid' />" + " <transition name='valid' to='simulated decision' />" + " </decision>" + " <decision name='simulated decision' expression='invalid'>" + " <transition name='first' to='end one' probability='0.2'/>" + " <transition name='second' to='end two' probability='0.4'/>" + " <transition name='third' to='end three' probability='0.4'/>" + " <transition name='invalid' to='end invalid' probability='0.0'/>" + " </decision>" + " <end-state name='end one'/>" + " <end-state name='end two'/>" + " <end-state name='end three'/>" + " <end-state name='end invalid'/>" + "</process-definition>" ; Experiment exp = new Experiment(getName(), "target"); exp.setShowProgressBar(false); DefaultJbpmSimulationModel model = new DefaultJbpmSimulationModel(processXml); model.connectToExperiment(exp); // start a process instance, which generates events ProcessInstance processInstance = new ProcessInstance(model.getProcessDefinitions()[0]); SimulationInstance simulationInstance = (SimulationInstance)processInstance.getInstance(SimulationInstance.class); simulationInstance.setExperiment(model); processInstance.signal(); exp.stop(new SimTime(3)); exp.setShowProgressBar(false); exp.start(); exp.report(); exp.finish(); assertTrue(processInstance.hasEnded()); assertNotSame("end invalid", processInstance.getRootToken().getNode().getName()); } public TaskInstance findTaskInstance(String taskName, ProcessInstance processInstance) { TaskMgmtInstance tmi = processInstance.getTaskMgmtInstance(); Iterator iter = tmi.getTaskInstances().iterator(); while (iter.hasNext()) { TaskInstance taskInstance = (TaskInstance) iter.next(); if ( (taskName.equals(taskInstance.getName()) && (!taskInstance.hasEnded()) && (taskInstance.getStart()!=null)) ) { return taskInstance; } } return null; } // old test: // setCurrentTime("10:29"); // pi1.signal(); // // setCurrentTime("10:35"); // exp.start(); // ProcessInstance pi2 = new ProcessInstance(processDefinition); // simulationInstance = (SimulationInstance)pi2.getInstance(SimulationInstance.class); // simulationInstance.setExperiment(simulationModel); // // setCurrentTime("10:46"); // pi2.signal(); // // assertNull(findTaskInstance("test", pi2)); // // setCurrentTime("10:55"); // TaskInstance taskInstance = findTaskInstance("test", pi1); // taskInstance.end(); // // produceReports(pi1); }