Documentation:Old Playing with EMF

From Tom

Revision as of 08:11, 13 October 2012 by Jcb (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search
Doc : Tutorial

Level 1 - Introduction  > Level 2 - List matching  > Level 3 - Strategies  > Advanced - Mappings  > Writing a (small) Parser/Compiler/Interpreter  > XML  > Playing with EMF

Warning: This page is currently refactored (introduction to %transformation construct)

This section deals with using Tom to handle EMF models by using Tom-EMF mappings generator and the new %transformation construct in a Tom program.

We propose to illustrate the use of the EMF mappings generator with the following example: we specify a process in a simple PDL formalism, and we want to transform it into a Petri net. (Here is an explanation of the transformation SimplePDL2Tina -in french)

Our use case consist in a models transformation, from SimplePDL formalism to PetriNet formalism. In the "MetaModels" section, we explain the two metamodels we use for the transformation; in the SimplePDL2PetriNet transformation section we describe the transformation itself with the implementation and we give the SimplePDL instance we choose; in the "Running" section we show how to run the example. The last section allows you to download all resources we use for this example.


Contents

MetaModels

Our models are defined as follow by using Eclipse with the modeling module.


Source MetaModel: SimplePDL

Image:simplePDL3c.png

To generate this diagram, you can import the SimplePDL.ecore file into your Eclipse project and use the 'generate ecore diagram' functionality. In this model, there is a notion of hierarchy : an activity (WorkDefinition) can be described by a process.


Target MetaModel: Petri Net

Image:netofpetri_ecorediag.png

To generate this diagram, you can import the NetOfPetri.ecore file into your Eclipse project and use the 'generate ecore diagram' functionality.


Generating model code

If you don't know how to generate model code using EMF, you should have a look at this tutorial. In this example, we will use the following ecore metamodels you can import into your Eclipse project to generate the EMF Java code:

Another possible solution consists in downloading the two corresponding java files we have generated with Eclipse from previous Ecore metamodels :

Generating EMF mappings

To generate EMF mappings, you will need to compile the EMF mapping generator.

Add needed EMF jars to CLASSPATH :

$ export CLASSPATH=`echo ${TOM_HOME}/lib/tools/org.eclipse.emf*.jar | tr ' ' ':'`:${CLASSPATH}

Note: This step is not necessary if you have installed Tom on Windows with the automatic installer.

This generator takes the generated EPackage class as argument. For example :

$ emf-generate-mappings -cp petrinetsemantics_1.0.0.jar petrinetsemantics.DDMMPetriNet.DDMMPetriNetPackage
$ mv petrinetsemantics.DDMMPetriNet.DDMMPetriNetPackage.tom DDMMPetriNetPackage.tom
$ emf-generate-mappings -cp simplepdlsemantics_1.1.0c.jar simplepdl.SimplepdlPackage
$ mv simplepdl.SimplepdlPackage.tom SimplePDL3c.tom

You can also download the two mapping files we have generated (with Tom-EMF 2.8, no subtyping): DDMMPetriNetPackage.tom and SimplePDL3c.tom.


Note: if DDMMPetriNetPackage and SimplepdlPackage are in the classpath, you do not need to use -cp java command option.

Note: You can generate Ecore metamodel mapping thanks to the following line :

emf-generate-mappings org.eclipse.emf.ecore.EcorePackage 

Using generated mappings

SimplePDL2PetriNet transformation

The principle of this transformation is:

  • to decompose it into several simple transformations
  • to execute these atomic transformation in any order
  • to replace temporary results (obtained during the previous phase) by final results

This transformation is composed of four main parts:

  • three elementary transformations:
    • Process2Petrinet
    • WorkDefinition2PetriNet
    • WorkSequence2PetriNet
  • a strategy that recompose the final result from each elementary result: Resolve

Each of these parts is represented by a Tom strategy. Since we are working with EMF code, we use a specific introspector (EcoreContainmentIntrospector) which only follows containment features to avoid looping problems.

Before describing these transformations, we begin with some mandatory code to understand and run the example:

import org.eclipse.emf.common.util.*;
import org.eclipse.emf.ecore.*;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
 
//we import here the Java generated code
import simplepdl.*;
import petrinetsemantics.DDMMPetriNet.*;
 
import java.util.*;
 
import tom.library.sl.*;
import tom.library.emf.*;
 
public class SimplePDLToPetri3c {
 
  %include{ sl.tom }
  //let's include the generated mappings
  %include{ DDMMPetriNetPackage.tom }
  %include{ SimplePDL3c.tom }
 
  %typeterm SimplePDLToPetri3c { implement { SimplePDLToPetri3c }}
 
  private Hashtable<Object,HashMap<String,Object>> table;
  private PetriNet pn = null;
 
  public SimplePDLToPetri3c() {
    this.table = new Hashtable<Object,HashMap<String,Object>>();
  }

Then, when we will use 'translator', it will refer to a SimplePDLToPetri3c object.

We also need few mappings and their associated inner classes that we defined as follow :

%op Place ResolveWorkDefinitionPlace(o:WorkDefinition, name:String) {
    is_fsym(t)        { $t instanceof ResolveWorkDefinitionPlace }
    get_slot(name, t) { ((ResolveWorkDefinitionPlace)$t).name }
    get_slot(o, t)    { ((ResolveWorkDefinitionPlace)$t).o }
    make(o,name)      { new ResolveWorkDefinitionPlace(o,name) }
  }
 
  %op Transition ResolveWorkDefinitionTransition(o:WorkDefinition,name:String) {
    is_fsym(t)        { $t instanceof ResolveWorkDefinitionTransition }
    get_slot(name, t) { ((ResolveWorkDefinitionTransition)$t).name }
    get_slot(o, t)    { ((ResolveWorkDefinitionTransition)$t).o }
    make(o,name)      { new ResolveWorkDefinitionTransition(o,name) }
  }
 
  %op Transition ResolveProcessTransition(o:Process,name:String) {
    is_fsym(t)        { $t instanceof ResolveProcessTransition }
    get_slot(name, t) { ((ResolveProcessTransition)$t).name }
    get_slot(o, t)    { ((ResolveProcessTransition)$t).o }
    make(o,name)      { new ResolveProcessTransition(o,name) }
  }
 
 
  private static class ResolveWorkDefinitionPlace extends petrinetsemantics.DDMMPetriNet.impl.PlaceImpl {
    public String name;
    public simplepdl.WorkDefinition o;
    public ResolveWorkDefinitionPlace(simplepdl.WorkDefinition o, String name) {
      this.name = name;
      this.o = o;
    }
  }
 
  private static class ResolveWorkDefinitionTransition extends petrinetsemantics.DDMMPetriNet.impl.TransitionImpl {
    public String name;
    public simplepdl.WorkDefinition o;
    public ResolveWorkDefinitionTransition(simplepdl.WorkDefinition o, String name) {
      this.name = name;
      this.o = o;
    }
  }
 
  private static class ResolveProcessTransition extends petrinetsemantics.DDMMPetriNet.impl.TransitionImpl {
    public String name;
    public simplepdl.Process o;
    public ResolveProcessTransition(simplepdl.Process o, String name) {
      this.name = name;
      this.o = o;
    }
  }

These mappings allow to create intermediate nodes used to transform the links between processes and activities, i.e. to store sources and targets of arcs while waiting for the final resolution. They extends Place and Transition implementations.


Process2Petrinet

The first transformation creates a Petrinet every time it detects a Process. As described in the previous model, a PetriNet is composed of Nodes (Places and Transitions) and Arcs. We represent them with ELists.

%strategy Process2PetriNet(translator:SimplePDLToPetri3c) extends Identity() {
    visit Process {
      p@Process[name=name] -> {
 
        /* Nodes of the Process image */
        Node p_ready  = `Place(name + "_ready", translator.pn,ArcEList(), ArcEList(), 1);
        Node p_running  = `Place(name + "_running", translator.pn,ArcEList(), ArcEList(), 0);
        Node p_finished  = `Place(name + "_finished", translator.pn,ArcEList(), ArcEList(), 0);
        Node t_start  = `Transition(name + "_start", translator.pn,ArcEList(), ArcEList(), 1, 1);
        Node t_finish  = `Transition(name + "_finish", translator.pn,ArcEList(), ArcEList(), 1, 1);
 
        `Arc(t_start, p_ready, translator.pn,normal(), 1);
        `Arc(p_running, t_start, translator.pn,normal(), 1);
        `Arc(t_finish, p_running, translator.pn,normal(), 1);
        `Arc(p_finished, t_finish, translator.pn,normal(), 1);
 
        HashMap<String,Object> map = new HashMap<String,Object>();
        map.put("p_ready",p_ready);
        map.put("p_running",p_running);
        map.put("p_finished",p_finished);
        map.put("t_start",t_start);
        map.put("t_finish",t_finish);
 
        translator.table.put(`p,map);
 
        WorkDefinition from = `p.getFrom();
        /*no need to create a ResolveWorkDefinitionTransition in case of the root process*/
        if (from!=null) {
          Transition source = new ResolveWorkDefinitionTransition(from, "t_start");
          source.setNet(translator.pn);
          Arc tmpZoomIn = `Arc(p_ready,source,translator.pn,normal(), 1);
 
          Transition target = new ResolveWorkDefinitionTransition(from, "t_finish");
          target.setNet(translator.pn);
          Arc tmpZoomOut = `Arc(target,p_finished,translator.pn,read_arc(), 1);
        }
      }
    }
  }

This strategy was very simple without any hierarchy between proccesses. However, since a WorkDefinition can be represented by a Process, we had to modify it.

First, we create the image of the Process by the transformation described in this use case. It is composed of three places and two transitions, as shown on the right. Then, all nodes are saved in an HashMap ('map') which is itself saved into the table (an attribute of the translator) as an hashmap entry. It will be useful during the final links resolution. Finally, in the case of non-root processes, two Arcs are created between the Process and the activity it describes. Since the strategy visits a Process and "knows" it, it needs only one intermediate node (ResolveWorkDefinitionTransition) for each Arc.

Petri net representing a Process
Petri net representing a Process


WorkDefinition2PetriNet

The second transformation is made by this strategy:

%strategy WorkDefinition2PetriNet(translator:SimplePDLToPetri3c) extends Identity() {
    visit WorkDefinition {
      wd@WorkDefinition[name=name] -> {
 
        Node p_ready  = `Place(name + "_ready", translator.pn,ArcEList(), ArcEList(), 1);
        Node p_started  = `Place(name + "_started", translator.pn,ArcEList(), ArcEList(), 0);
        Node p_running  = `Place(name + "_running", translator.pn,ArcEList(), ArcEList(), 0);
        Node p_finished  = `Place(name + "_finished", translator.pn,ArcEList(), ArcEList(), 0);
        Node t_start  = `Transition(name + "_start", translator.pn,ArcEList(), ArcEList(), 1, 1);
        Node t_finish  = `Transition(name + "_finish", translator.pn,ArcEList(), ArcEList(), 1, 1);
 
 
        `Arc(t_start, p_ready, translator.pn,normal(), 1);
        `Arc(p_started, t_start, translator.pn,normal(), 1);
        `Arc(p_running, t_start, translator.pn,normal(), 1);
        `Arc(t_finish, p_running, translator.pn,normal(), 1);
        `Arc(p_finished, t_finish, translator.pn,normal(), 1);
 
        HashMap<String,Object> map = new HashMap<String,Object>();
        map.put("p_ready",p_ready);
        map.put("p_started",p_started);
        map.put("p_running",p_running);
        map.put("p_finished",p_finished);
        map.put("t_start",t_start);
        map.put("t_finish",t_finish);
 
        translator.table.put(`wd,map);
 
        /* here we create the two links between parent Process and WorkDefinition */
        simplepdl.Process parent = `wd.getParent();
        Transition source = new ResolveProcessTransition(parent , "t_start");
        source.setNet(translator.pn);
        Arc tmpDistribute = `Arc(p_ready,source,translator.pn,normal(), 1);
 
        Transition target = new ResolveProcessTransition(parent, "t_finish");
        target.setNet(translator.pn);
        Arc tmpRejoin = `Arc(target,p_finished,translator.pn,read_arc(), 1);
      }
    }
  }

Each WorkDefinition is transformed into a Petri net representing an activity, composed of Places, Transitions and Arcs. The diagram on the right shows how this Petri net should look like.

In this strategy, we create the corresponding PetriNet (places, transitions and arcs). After that, as in the previous strategy, all nodes are saved in an HashMap ('map') which is itself saved into the table (an attribute of the translator) as an hashmap entry. Since a Process is not representeed by a single activity but by a Petri net, and since it composed of many activities, it is necessary to link each activity to the parent process. Therefore, two Arcs are created between each activity and its parent process. As in the previous strategy, the current term which is visited (a WorkDefinition) does not "know" other structures like Process. Intermediate nodes (ResolveProcessTransition) are then used for those Arcs.

Petri net representing an activity
Petri net representing an activity


WorkSequence2PetriNet

The third transformation consists in a strategy that creates links between activities of a same process:

%strategy WorkSequence2PetriNet(translator:SimplePDLToPetri3c) extends Identity() {
    visit WorkSequence {
      WorkSequence[predecessor=p,successor=s,linkType=linkType] -> { 
        Place source= null;
        Transition target= null;
        %match(linkType) { 
          (finishToFinish|finishToStart)[] -> { source = new ResolveWorkDefinitionPlace(`p,"p_finished"); }
          (startToStart|startToFinish)[]   -> { source = new ResolveWorkDefinitionPlace(`p,"p_started"); }
 
          (finishToStart|startToStart)[]   -> { target = new ResolveWorkDefinitionTransition(`s,"t_start"); }
          (startToFinish|finishToFinish)[] -> { target = new ResolveWorkDefinitionTransition(`s,"t_finish"); }
        }
        source.setNet(translator.pn);
        target.setNet(translator.pn);
        Arc tmp = `Arc(target,source, translator.pn,read_arc(), 1);  
      }
    }
  }

In this part, we used two intermediate types of nodes (ResolveWorkDefinitionPlace and ResolveWorkDefinitionTransition) to create an Arc between two activities. In the Petri net case, this type of link is represented by a read-arc which controls that a transition is enabled (it checks if a token is present).


Resolve

/*
    * @param resolveNode temporary ResolveNode that should be replaced
    * @param newNode node (stored in the HashMap) that will replace the ResolveNode
    * @param translator the TimplePDLToPetri3
    */
  public static void resolveInverseLinks(EObject resolveNode, Node newNode, SimplePDLToPetri3c translator) {
    /* collect arcs having ResolveWorkDefinitionPlace and ResolveWorkDefinitionTransition */
 
    ECrossReferenceAdapter adapter = new ECrossReferenceAdapter(); //create an adapter
    translator.pn.eAdapters().add(adapter); //attach it to PetriNet
 
    /*
     * 'references' will contains a set of objects (i.e.
     * EStructuralFeature.Setting) from which we can retrieve 
     * (thanks to getEObject()) objects that
     * contains references (i.e. pointers) to resolveNode
     */
    Collection<EStructuralFeature.Setting> references = adapter.getInverseReferences(resolveNode);
 
    // for each type of Resolve
    boolean toSet = (false
        | resolveNode instanceof ResolveWorkDefinitionPlace 
        | resolveNode instanceof ResolveWorkDefinitionTransition
        | resolveNode instanceof ResolveProcessTransition
        );
 
    for (EStructuralFeature.Setting setting:references) {
      // current is an object that references resolveNode
      EObject current = setting.getEObject();
      if (current instanceof Arc) {
        Arc newCurrent = (Arc)current;
          // for each field of Arc
        if(newCurrent.getSource().equals(resolveNode) && toSet) {
          newCurrent.setSource(newNode); 
        } else if(newCurrent.getTarget().equals(resolveNode) && toSet) {
          newCurrent.setTarget(newNode); 
        } else {
          throw new RuntimeException("should not be there");
        }
      }
    }
 
  }
 
  /*
   * Strategy that replaces all Resolve nodes by a normal node
   */
  %strategy Resolve(translator:SimplePDLToPetri3c) extends Identity() {
    visit Place {
      pr@ResolveWorkDefinitionPlace[o=o,name=name] -> {
        Place res = (Place) translator.table.get(`o).get(`name);
        resolveInverseLinks(`pr, res, translator);
        return res;
      }
    }
 
    visit Transition {
      tr@ResolveWorkDefinitionTransition[o=o,name=name] -> {
        Transition res = (Transition) translator.table.get(`o).get(`name);
        resolveInverseLinks(`tr, res, translator);
        return res;
      }
      ptr@ResolveProcessTransition[o=o,name=name] -> {
        Transition res = (Transition) translator.table.get(`o).get(`name);
        resolveInverseLinks(`ptr, res, translator);
        return res;
      }
    }
 
  }

This chunk of code allows to resolve links between different WorkDefinition, WorkDefinition and parent Process, and between WorkDefinition and describing Process. The Resolve strategy is visiting the PetriNet in order to find and replace all intermediate nodes previously created. All ResolveWorkDefinitionPlace, ResolveWorkDefinitionTransition and ResolveProcessTransition are replaced by the appropriate node obtained by using the HashTable table. Before returning this node, it is important to update the different links : indeed, if this step is not done, the arcs we created during a previous step are not updated. When updating the Petri net, the strategy follows composition associations, therefore Petri net nodes are updated and not arcs. At the end of the transformation, the resulting Petri net will not be correct since arcs coming from WorkSequence transformations will still have intermediate nodes as sources and targets. To have a complete transformation, inverse links have to be updated. For that, we call resolveInverseLinks that uses an EMF mechanism to get inverse links by creating an ECrossReferenceAdapter and calling its getInverseReferences method.

Before finishing

To have a fully working example, some code has to be added:

  • strategies which allow to print the different nodes by respecting few notation conventions:
%strategy PrintArc() extends Identity() {
    visit Arc {
      Arc[source=node1, target=node2] -> {
        System.out.println(`node1.getName() + " -> " + `node2.getName());
      }
    }
  }
 
  %strategy PrintTransition() extends Identity() {
    visit Transition {
      tr@ResolveWorkDefinitionTransition[o=o,name=name] -> {
        System.out.println("tr resolve " + `name);
        return `tr;
      }
 
      ptr@ResolveProcessTransition[o=o,name=name] -> {
        System.out.println("tr process resolve " + `name);
        return `ptr;
      }
 
      Transition[name=name,incomings=sources,outgoings=targets] -> {
        String s = "";
        String t = "";
        %match {
         ArcEList(_*,Arc[kind=k,weight=w,source=node],_*) << sources && Place[name=placename]<< node -> {
           s += `placename + ((`k==`read_arc())?"?":"*") + `w + " "; 
         }
         ArcEList(_*,Arc[kind=k,weight=w,target=node],_*) << targets && Place[name=placename]<< node -> { 
           t += `placename + ((`k==`read_arc())?"?":"*") + `w + " "; 
         }
        }
        System.out.println("tr " + `name + " " + s + " --> " + t);
      }
 
    }
  }
 
  %strategy PrintPlace() extends Identity() {
    visit Place {
      pl@ResolveWorkDefinitionPlace[o=o,name=name] -> {
        System.out.println("pl resolve " + `name);
        return `pl;
      }
 
      Place[name=name,initialMarking=w] && w!=0 -> {
        System.out.println("pl " + `name + " " + `w);
      }
 
    }
  }
  • the main procedure where we create the example's elements (WorkDefinitions and WorkSequences):
public static void main(String[] args) {
    System.out.println("bonne compilation (v3c)\n .......");
    /*
     Use case : 
       wd1 -> A 
       wd2 -> B
       wd3 -> C
       wd4 -> D
       ws1(wd1,wd2,S2S)
       ws2(wd3,wd4,S2F)
       P_root : wd1 + wd2
       P_child : wd3 + wd4
       P_child = description of wd2
     */
 
    /* parent is null since processes have not been yet created */
    WorkDefinition wd1 = `WorkDefinition(null,WorkSequenceEList(),WorkSequenceEList(),null,"A");
    WorkDefinition wd2 = `WorkDefinition(null,WorkSequenceEList(),WorkSequenceEList(),null,"B");
    WorkDefinition wd3 = `WorkDefinition(null,WorkSequenceEList(),WorkSequenceEList(),null,"C");
    WorkDefinition wd4 = `WorkDefinition(null,WorkSequenceEList(),WorkSequenceEList(),null,"D");
    WorkSequence ws1 = `WorkSequence(null,startToStart(),wd1,wd2);
    WorkSequence ws2 = `WorkSequence(null,startToFinish(),wd3,wd4);
 
    simplepdl.Process p_root = `Process("root",ProcessElementEList(wd1,wd2,ws1),null);
    simplepdl.Process p_child = `Process("child",ProcessElementEList(wd3,wd4,ws2),wd2);
 
    /* 
     * - Set parent to each ProcessElement (each WorkDefinition and
     * WorkSequecence has a parent process)
     * - Add the child process to the processes list which is the implementation of
     * the composition association between 'WorkDefinition' and 'Process'
     */
    wd1.setParent(p_root);
    wd2.setParent(p_root);
    wd2.setProcess(p_child);
 
    wd3.setParent(p_child);
    wd4.setParent(p_child);
 
    ws1.setParent(p_root);
    ws2.setParent(p_child);
 
    SimplePDLToPetri3c translator = new SimplePDLToPetri3c();
 
    try {
 
      /*
       * The PetriNet is created onece and for all, before performing any strategy
       */
      translator.pn = `PetriNet(NodeEList(),ArcEList(),"main");
 
      /*
       * Transformation : Process to PetriNet
       * - Process to PetriNet
       * - WorkDefinition to PetriNet
       * - WorkSequence to PetriNet
       */
      Strategy transformer = `Sequence(
          TopDown(Process2PetriNet(translator)),
          TopDown(WorkDefinition2PetriNet(translator)),
          TopDown(WorkSequence2PetriNet(translator))
       );
      transformer.visit(p_root, new EcoreContainmentIntrospector());
 
      System.out.println("\nBefore Resolve");
      `Sequence(TopDown(PrintTransition()),TopDown(PrintPlace())).visit(translator.pn, new EcoreContainmentIntrospector());
 
      System.out.println("\nTest strategy resolve");
      `TopDown(Resolve(translator)).visit(translator.pn,new EcoreContainmentIntrospector());
 
      System.out.println("\nAfter Resolve");
      `Sequence(TopDown(PrintTransition()),TopDown(PrintPlace())).visit(translator.pn, new EcoreContainmentIntrospector());
 
    } catch(VisitFailure e) {
        System.out.println("strategy fail");
    }
  }

In the main procedure, we create all objects we want to transform (processes, work definitions, work sequences). To run our transformation, we choose the following instance of SimplePDL metamodel:

  • the main Process is named root
  • root Process is composed of two WorkDefinitions (wd1/A & wd2/B) and one WorkSequence (ws1)
  • wd2 WorkDefinition is described by an other Process, named child
  • child Process is composed of two WorkDefinitions (wd3/C & wd4/D) and one WorkSequence (ws2)
  • WorkSequences connect the WorkDefinitions as follow:
    • ws1: wd1 has to to be started to start wd2 (StartToStart)
    • ws2: wd3 has to be started to finish wd4 (StartToFinish)

We also create once for all the Petri net we populate during the transformations (by addings nodes and arcs). Then, we call the strategies in sequence, and the output is:

 bonne compilation (v3c)
 .......
 
 Before Resolve
 tr root_start root_ready*1  --> root_running*1 
 tr root_finish root_running*1  --> root_finished*1 
 tr child_start child_ready*1  --> child_running*1 
 tr child_finish child_running*1  --> child_finished*1 
 tr resolve t_start
 tr resolve t_finish
 tr A_start A_ready*1  --> A_started*1 A_running*1 
 tr A_finish A_running*1  --> A_finished*1 
 tr process resolve t_start
 tr process resolve t_finish
 tr B_start B_ready*1  --> B_started*1 B_running*1 
 tr B_finish B_running*1  --> B_finished*1 
 tr process resolve t_start
 tr process resolve t_finish
 tr C_start C_ready*1  --> C_started*1 C_running*1 
 tr C_finish C_running*1  --> C_finished*1 
 tr process resolve t_start
 tr process resolve t_finish
 tr D_start D_ready*1  --> D_started*1 D_running*1 
 tr D_finish D_running*1  --> D_finished*1 
 tr process resolve t_start
 tr process resolve t_finish
 tr resolve t_finish
 tr resolve t_start
 pl root_ready 1
 pl child_ready 1
 pl A_ready 1
 pl B_ready 1
 pl C_ready 1
 pl D_ready 1
 pl resolve p_started
 pl resolve p_started
 
 Test strategy resolve
 
 After Resolve
 tr root_start root_ready*1  --> root_running*1 A_ready*1 B_ready*1 
 tr root_finish root_running*1 A_finished?1 B_finished?1  --> root_finished*1 
 tr child_start child_ready*1  --> child_running*1 C_ready*1 D_ready*1 
 tr child_finish child_running*1 C_finished?1 D_finished?1  --> child_finished*1 
 tr B_start B_ready*1 A_started?1  --> B_started*1 B_running*1 child_ready*1 
 tr B_finish B_running*1 child_finished?1  --> B_finished*1 
 tr A_start A_ready*1  --> A_started*1 A_running*1 
 tr A_finish A_running*1  --> A_finished*1 
 tr C_start C_ready*1  --> C_started*1 C_running*1 
 tr C_finish C_running*1  --> C_finished*1 
 tr D_start D_ready*1  --> D_started*1 D_running*1 
 tr D_finish D_running*1 C_started?1  --> D_finished*1 
 pl root_ready 1
 pl child_ready 1
 pl A_ready 1
 pl B_ready 1
 pl C_ready 1
 pl D_ready 1

WorkDefinitions, WorkSequences and Processes will be transformed into this Petri net:

Image:CompleteProcess.png


Running the example

To run the studied example, just execute the following commands:

For Unix-like systems:

tom -p SimplePDLToPetri3c.t
javac -cp simplepdlsemantics_1.1.0c.jar:petrinetsemantics_1.0.0.jar:$CLASSPATH SimplePDLToPetri3c.java
java -cp simplepdlsemantics_1.1.0c.jar:petrinetsemantics_1.0.0.jar:$CLASSPATH SimplePDLToPetri3c

For Windows systems:

tom -p SimplePDLToPetri3c.t
javac -cp "simplepdlsemantics_1.1.0c.jar;petrinetsemantics_1.0.0.jar;%CLASSPATH%" SimplePDLToPetri3c.java
java -cp "simplepdlsemantics_1.1.0c.jar;petrinetsemantics_1.0.0.jar;%CLASSPATH%" SimplePDLToPetri3c

Downloadable resources

You can download here useful files for this example:

Tutorial

Level 1 - Introduction  > Level 2 - List matching  > Level 3 - Strategies  > Advanced - Mappings  > Writing a (small) Parser/Compiler/Interpreter  > XML  > Playing with EMF

Tom Documentation
Guided Tour :: Tutorial :: Language Reference :: Tools
Personal tools
Create a book