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

org.jbpm.sim.exe.ExperimentReader Maven / Gradle / Ivy

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

import java.io.StringReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.jbpm.graph.def.Event;
import org.jbpm.graph.def.GraphElement;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.def.Transition;
import org.jbpm.jpdl.xml.JpdlParser;
import org.jbpm.jpdl.xml.Problem;
import org.jbpm.jpdl.xml.ProblemListener;
import org.jbpm.sim.datasource.UseDataFilterAction;
import org.jbpm.sim.datasource.UseDataSourceAction;
import org.jbpm.sim.def.DistributionDefinition;
import org.jbpm.sim.def.JbpmSimulationExperiment;
import org.jbpm.sim.def.JbpmSimulationScenario;
import org.jbpm.sim.exception.ExperimentConfigurationException;
import org.jbpm.sim.jpdl.SimulationDefinition;
import org.jbpm.sim.jpdl.SimulationJpdlXmlReader;
import org.jbpm.sim.kpi.BusinessFigure;
import org.jbpm.sim.kpi.BusinessFigureAction;
import org.jbpm.taskmgmt.def.Task;
import org.xml.sax.InputSource;

/**
 * The ExperimentReader is responsible for creating a 
 * org.jbpm.sim.exe.JbpmSimulationExperiment out of 
 * the experiment XML.
 * 
 * @author [email protected]
 */
public class ExperimentReader implements ProblemListener {
  
  private static Log log = LogFactory.getLog(ExperimentReader.class);

  private InputSource inputSource = null;
  protected Document experimentDoc;
  
  private JbpmSimulationExperiment experiment;
  
  /**
   * internal registry of process definitions used in a experiment.
   * 
   * Especially useful if you want to use process definitions which 
   * can not be discovered by the reader itself (for example in unit tests) 
   */
  private Map processDefinitionRepository = new HashMap();
  
  public ExperimentReader(String experimentXml) {
    this(new InputSource(new StringReader(experimentXml)));
  }

  public ExperimentReader(InputSource inputSource) {
    this.inputSource = inputSource;
  }

  protected Document getXmlDocument() {
    if(experimentDoc==null) {
      try {
        experimentDoc = JpdlParser.parse(inputSource, this);
      }
      catch (Exception e) {
        throw new ExperimentConfigurationException("Couldn't read experiment XML", e);
      }
    }
    return experimentDoc;
  }

  public void addProblem(Problem problem) {
    log.warn("problem occured while parsing XML: " + problem);
    // TODO: implement addProblem (can be called from JpdlParser)    
  }
  
  /**
   * add a process definition to this reader, which can be referenced from a sim-process
   * in a experiment. This is useful in test cases, where you don't store the
   * process in a XML file, but as a String. 
   */
  public void addProcessDefinition(String processName, String processXml) {
    /*
     * we can not parse the ProcessDefinition here, because
     * if we have multiple scenarios, they save information about
     * resource pools or distributions in the SImulationDefinition
     * module of the processDefinition object. So only save the XML,
     * so we can create as many objects as we want from it
     */
    processDefinitionRepository.put(processName, processXml);
  }
  
  public JbpmSimulationExperiment readExperiment()  {
    Element root = getXmlDocument().getRootElement();

    String name = root.attributeValue("name");
    experiment = new JbpmSimulationExperiment(name);
    
    // read basic attributes
    String runTimeString = root.attributeValue("run-time");
    String resetTime = root.attributeValue("reset-time");
    String realStartTimeString = root.attributeValue("real-start-time");
    String timeUnitString = root.attributeValue("time-unit");
    String currencyString = root.attributeValue("currency");
    String unutilizedTimeCostFactorString = root.attributeValue("unutilized-time-cost-factor");
    
    if (currencyString!=null)
      experiment.setCurrency( currencyString );
    if (unutilizedTimeCostFactorString!=null)
      experiment.setUnutilizedTimeCostFactor(Double.parseDouble(unutilizedTimeCostFactorString));
      
    if (runTimeString!=null)
      experiment.setSimulationRunTime( Double.parseDouble(runTimeString) );
    if (resetTime!=null)
      experiment.setResetTime( Double.parseDouble(resetTime) );
    if (realStartTimeString!=null)
      experiment.setRealStartDate( realStartTimeString );
    
    if (timeUnitString!=null) {
      timeUnitString = timeUnitString.toLowerCase(); 
      if ("millisecond".equals(timeUnitString))
        experiment.setTimeUnit( JbpmSimulationExperiment.MILLISECONDS );
      else if ("second".equals(timeUnitString))
        experiment.setTimeUnit( JbpmSimulationExperiment.SECONDS );
      else if ("minute".equals(timeUnitString))
        experiment.setTimeUnit( JbpmSimulationExperiment.MINUTES );
      else if ("hour".equals(timeUnitString))
        experiment.setTimeUnit( JbpmSimulationExperiment.HOURS );
    }    
    
    // read output parameters
    Element outputElement = root.element("output");
    if (outputElement!=null) {
      String outputPathName = outputElement.attributeValue("path");
      experiment.setOutputPathName(outputPathName);
    }
    
    // read scenarios
    Iterator scenarioIterator = root.elementIterator("scenario");
    while (scenarioIterator.hasNext()) {
      Element scenarioElement = (Element) scenarioIterator.next();
      String baseScenario = scenarioElement.attributeValue("base-scenario");
      if (baseScenario!=null) {
        Element baseScenarioElement = null;
        Iterator iter2 = root.elementIterator("scenario");
        while (iter2.hasNext()) {
          Element e = (Element) iter2.next();
          if (baseScenario.equals( e.attributeValue("name") )) {
            baseScenarioElement = e;
            break;
          }
        }
        if (baseScenarioElement==null)
          throw new ExperimentConfigurationException("base scenario with name '" + baseScenario + "' does not exist");
        addScenario(
            readScenario(scenarioElement, baseScenarioElement));
      }
      else
        addScenario(
            readScenario(scenarioElement, null));
    }
    
    JbpmSimulationExperiment result = experiment;
    experiment = null;
    return result;
  }
  
  protected void addScenario(JbpmSimulationScenario scenario) {
    experiment.addScenario(scenario);
  }
  
  public static DistributionDefinition readDistribution(Element distributionElement) {
    String name = distributionElement.attributeValue("name");
    String sampleType = distributionElement.attributeValue("sample-type");
    String type = distributionElement.attributeValue("type");

    String valueText = distributionElement.attributeValue("value");
    String meanText = distributionElement.attributeValue("mean");
    String standardDeviationText = distributionElement.attributeValue("standardDeviation");
    String minText = distributionElement.attributeValue("min");
    String maxText = distributionElement.attributeValue("max");
    String nonNegativeText = distributionElement.attributeValue("nonNegative");

    boolean nonNegative = ("true".equals(nonNegativeText) || "yes".equals(nonNegativeText));

    return new DistributionDefinition( //
        name, type, sampleType, valueText, meanText, standardDeviationText, minText, maxText, nonNegative);
  }

  protected JbpmSimulationScenario readScenario(Element scenarioElement, Element baseScenarioElement) {
    String name = scenarioElement.attributeValue("name");
    JbpmSimulationScenario scenario = new JbpmSimulationScenario(name);

    String execute = scenarioElement.attributeValue("execute");
    if ("false".equalsIgnoreCase(execute)|| "no".equalsIgnoreCase(execute))
        scenario.setExecute(false);
    
    beforeScenarioRead(scenario, scenarioElement, baseScenarioElement);
    
    // TODO: Maybe a scenario just refers to a somehow "global" defined scenario
    // For the moment, only inline definition of the scenarios is supported

    if (baseScenarioElement!=null)
      readScenarioContent(baseScenarioElement, scenario);    
    
    // now read scenario, this overwrites data from base scenario
    readScenarioContent(scenarioElement, scenario);    

    afterScenarioRead(scenario, scenarioElement, baseScenarioElement);
    
    return scenario;
  }

  protected void afterScenarioRead(JbpmSimulationScenario scenario,
      Element scenarioElement, Element baseScenarioElement) {    
    // Empty, could be used to extend ExperimentReader    
  }

  protected void beforeScenarioRead(JbpmSimulationScenario scenario,
      Element scenarioElement, Element baseScenarioElement) {
    // Empty, could be used to extend ExperimentReader    
  }

  private void readScenarioContent(Element scenarioElement,
      JbpmSimulationScenario scenario) {
    // read processes
    Iterator processIterator = scenarioElement.elementIterator("sim-process");       
    while (processIterator.hasNext()) {
      Element processElement = (Element) processIterator.next();      
      readSimProcess(scenario, processElement);
    }
    
    // read distributions and maybe overwrite process definition configurations
    Iterator distributionIterator = scenarioElement.elementIterator("distribution");
    while (distributionIterator.hasNext()) {
      Element distributionElement = (Element) distributionIterator.next();
      DistributionDefinition distDef = ExperimentReader.readDistribution(distributionElement);      
      scenario.addDistribution(distDef);
    }    
    
    // read resource pools and maybe overwrite process definition configurations
    /*
     * read information of resource pools
     */
    Iterator poolElementIter = scenarioElement.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);
      scenario.addResourcePool(poolName, poolSize, readCostPerTimeUnit(resourcePoolElement));
    }
    
    // read business figures
    Iterator businessFigureIterator = scenarioElement.elementIterator("business-figure");
    while (businessFigureIterator.hasNext()) {
      Element figureElement = (Element) businessFigureIterator.next();
      BusinessFigure figure = new BusinessFigure(
          figureElement.attributeValue("name"),
          figureElement.attributeValue("type"),
          figureElement.attributeValue("handler"),
          figureElement.attributeValue("expression"));
      scenario.addBusinessFigure(figure);
    }     
    
    // read data source and filters
    Iterator dataSourceIterator = scenarioElement.elementIterator("data-source");
    while (dataSourceIterator.hasNext()) {
      Element dataSource = (Element) dataSourceIterator.next();
      scenario.addDataSource( //
          dataSource.attributeValue("name"), // name
          dataSource.attributeValue("handler")); // handler class name
    }     

    // read data source and filters
    Iterator dataFilterIterator = scenarioElement.elementIterator("data-filter");
    while (dataFilterIterator.hasNext()) {
      Element dataFilter = (Element) dataFilterIterator.next();
      scenario.addDataFilter( //
          dataFilter.attributeValue("name"), // name
          dataFilter.attributeValue("handler")); // handler class name
    }     
}
  
  protected Double readCostPerTimeUnit(Element resourcePoolElement) {
    String costPerTimeUnitText = resourcePoolElement.attributeValue("costs-per-time-unit");
    if (costPerTimeUnitText!=null)
      return Double.valueOf(costPerTimeUnitText);
    else
      return new Double(0);
  }  

  private void readSimProcess(JbpmSimulationScenario scenario, Element processElement) {
    String processName = processElement.attributeValue("name");
    String processPath = processElement.attributeValue("path");
    ProcessDefinition pd = null;
    
    // if in the local repository take it from there
    if (processName!=null && processDefinitionRepository.containsKey(processName)) {
      String processXml = (String) processDefinitionRepository.get(processName);
      SimulationJpdlXmlReader processReader = new SimulationJpdlXmlReader(processXml);
      pd = processReader.readProcessDefinition();
    }
    // if not the XML file should be read
    else if (processPath!=null) {
      InputSource source = new InputSource(this.getClass().getResourceAsStream(processPath));
      SimulationJpdlXmlReader processReader = new SimulationJpdlXmlReader(source);
      pd = processReader.readProcessDefinition();
    }
    else
      throw new ExperimentConfigurationException("references process (name='"+processName+"', path='"+processPath+"') in scenario '" + scenario.getName() + "' not found.");
    
    // read special overwrite statements
    Iterator processIter = processElement.elementIterator("process-overwrite");
    while(processIter.hasNext()) {
        readProcessOverwrite(pd, (Element)processIter.next());
    }
    Iterator stateIter = processElement.elementIterator("state-overwrite");
    while(stateIter.hasNext()) {
        readStateOverwrite(pd, (Element)stateIter.next());
    }
    Iterator decisionIter = processElement.elementIterator("decision-overwrite");
    while(decisionIter.hasNext()) {
        readDecisionOverwrite(pd, (Element)decisionIter.next());
    }
    Iterator taskIter = processElement.elementIterator("task-overwrite");
    while(taskIter.hasNext()) {
        readTaskOverwrite(pd, (Element)taskIter.next());
    }
    Iterator nodeIter = processElement.elementIterator("node-overwrite");
    while(nodeIter.hasNext()) {
        readNodeOverwrite(pd, (Element)nodeIter.next());
    }

    scenario.addProcessDefinition( pd );
  }

  private void readProcessOverwrite(ProcessDefinition pd, Element e) {
    String newStartDistribution = e.attributeValue("start-distribution");
    if (newStartDistribution!=null)
      ((SimulationDefinition)pd.getDefinition(SimulationDefinition.class)).setStartDistribution(newStartDistribution);

    readUseDataSourceEvent(pd.getStartState(), e, Event.EVENTTYPE_BEFORE_SIGNAL);
  }  

  private void readStateOverwrite(ProcessDefinition pd, Element e) {
    String stateName = e.attributeValue("state-name");
    String newDistribution = e.attributeValue("time-distribution");

    SimulationDefinition sd = ((SimulationDefinition)pd.getDefinition(SimulationDefinition.class));
    Node node = pd.getNode(stateName);
    
    if (newDistribution!=null)
      sd.addStateDistribution(node, newDistribution);
    
    readUseDataSourceEvent(node, e, Event.EVENTTYPE_NODE_ENTER);
    readUseDataFilterEvent(node, e, Event.EVENTTYPE_NODE_ENTER);
    readBusinessFigureEvent(node, e, Event.EVENTTYPE_NODE_ENTER);
    
    Iterator iter = e.elementIterator("transition");
    while (iter.hasNext()) {
      readTransitionOverwrite(sd, node, (Element)iter.next());
    }
  }
  
  private void readNodeOverwrite(ProcessDefinition pd, Element e) {
    String nodeName = e.attributeValue("node-name");
    Node node = pd.getNode(nodeName);

    readUseDataSourceEvent(node, e, Event.EVENTTYPE_NODE_ENTER);
    readUseDataFilterEvent(node, e, Event.EVENTTYPE_NODE_ENTER);
    readBusinessFigureEvent(node, e, Event.EVENTTYPE_NODE_ENTER);    
  }  

  private void readDecisionOverwrite(ProcessDefinition pd, Element e) {
    String decisionName = e.attributeValue("decision-name");

    SimulationDefinition sd = ((SimulationDefinition)pd.getDefinition(SimulationDefinition.class));
    Node node = pd.getNode(decisionName);
    
    Iterator iter = e.elementIterator("transition");
    while (iter.hasNext()) {
      readTransitionOverwrite(sd, node, (Element)iter.next());
    }
  }  

  private void readTaskOverwrite(ProcessDefinition pd, Element e) {
    String taskName = e.attributeValue("task-name");
    String newDistribution = e.attributeValue("time-distribution");
    
    SimulationDefinition sd = ((SimulationDefinition)pd.getDefinition(SimulationDefinition.class));
    Task task = pd.getTaskMgmtDefinition().getTask(taskName);

    if (newDistribution!=null) {
      sd.addTaskDistribution(task, newDistribution);
    }
    
    readUseDataSourceEvent(task.getTaskNode(), e, Event.EVENTTYPE_NODE_ENTER);
    readUseDataFilterEvent(task.getTaskNode(), e, Event.EVENTTYPE_NODE_ENTER);    
    readBusinessFigureEvent(task.getTaskNode(), e, Event.EVENTTYPE_NODE_ENTER);

    Iterator iter = e.elementIterator("transition");
    while (iter.hasNext()) {
      readTransitionOverwrite(sd, task.getTaskNode(), (Element)iter.next());
    }
  }
  
  private void readUseDataSourceEvent(GraphElement graphElement, Element xmlElement, String eventtype) {    
    Element e = xmlElement.element("use-data-source");
    if (e!=null) {
      Event evt = new Event(eventtype);
      UseDataSourceAction action = new UseDataSourceAction();
      action.setName( e.attributeValue("name") );
      evt.addAction( action );

      graphElement.addEvent(evt);
    }
  }

  private void readUseDataFilterEvent(GraphElement graphElement, Element xmlElement, String eventtype) {    
    Element e = xmlElement.element("use-data-filter");
    if (e!=null) {
      Event evt = new Event(eventtype);
      UseDataFilterAction action = new UseDataFilterAction();
      action.setName( e.attributeValue("name") );
      evt.addAction( action );

      graphElement.addEvent(evt);
    }
  }
  
  private void readBusinessFigureEvent(GraphElement graphElement, Element xmlElement, String eventtype) {    
    Element e = xmlElement.element("calculate-business-figure");
    if (e!=null) {
      Event evt = new Event(eventtype);
      BusinessFigureAction action = new BusinessFigureAction();
      action.setName( e.attributeValue("name") );
      evt.addAction( action );

      graphElement.addEvent(evt);
    }
  }  
  
  private void readTransitionOverwrite(SimulationDefinition sd, Node node, Element transitionElement) {
    String name = transitionElement.attributeValue("name");    
    Transition trans = node.getLeavingTransition(name);
    
    String probString = transitionElement.attributeValue( "probability" );
    if (probString!=null) {
      double prob = Double.parseDouble(probString);
      sd.addTransitionProbability(trans, prob);
    }

  }  
  
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy