public static ProcessDefinition createMilestoneProcessDefinition() {
    ProcessDefinition pd =
        new ProcessDefinition(
            new String[] {
              "start-state start",
              "fork fork",
              "state b",
              "milestone-node m",
              "state c",
              "state d",
              "join join",
              "end-state end"
            },
            new String[] {
              "start --> fork",
              "fork --m--> b",
              "fork --d--> d",
              "b --> m",
              "m --> c",
              "c --> join",
              "d --> join",
              "join --> end"
            });

    Node d = pd.getNode("d");

    Delegation instantiatableDelegate = new Delegation(new MilestoneEvent("m", "../m"));
    Event event = new Event(Event.EVENTTYPE_NODE_LEAVE);
    d.addEvent(event);
    event.addAction(new Action(instantiatableDelegate));

    pd.addDefinition(new ContextDefinition());

    return pd;
  }
  /**
   * 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"));
  }