0 Replies Latest reply on May 30, 2006 11:04 AM by Tom Baeyens

    xml versus java versus custom syntax

    Tom Baeyens Master

      If you're not familiar with the concept of DSL, this explains many things that i reuse in this post: http://martinfowler.com/articles/languageWorkbench.html This post is nothing fancy. Just an application of (some concepts in) that article.

      I see 4 possible ways to specify a process language. I want you to help in identifying pros and cons of each approach. They don't exclude each other. So it's not like you have to pick one out that you like best. Well... that is already helpfull, but i really would like to know all the arguments on when to use a perticular form of DSL and what form will be the most future proof given the current shift of IDEs towards support for custom XML and custom languages.

      1) building the process programmatically (as is now possible in jPDL):

      ProcessDefinition processDefinition = new ProcessDefinition("order");
       Node start = processDefinition.addNode(new StartState("start"));
       Node waitForApproval = processDefinition.addNode(new State("waitForApproval"));
       Transition t = start.addLeavingTransition(new Transition());
       t.setFrom(start);
       t.setTo(waitForApproval);
       ...
      


      I think you get the picture. All the objects are constructed programmatically and all the wiring is done in code.

      pros: simple and straightforward. least curve for a java programmer.
      cons: verbose. difficult to see the structure of the objectgraph that you're creating. tedious to update/maintain.

      2) another approach is to embed the process language in XML. (as we do now in jPDL)

      <process-definition name="websale"
       xmlns="urn:jbpm.org:jpdl-3.1">
      
       <swimlane name="buyer" />
       ...
       <start-state name="create new web sale order">
       <task swimlane="buyer">
       <controller>
       <variable name="item"/>
       <variable name="quantity"/>
       <variable name="address"/>
       </controller>
       </task>
       <transition to="evaluate web order" />
       </start-state>
      
       <task-node name="evaluate web order">
       <task swimlane="salesman">
       <timer duedate="20 seconds" repeat="10 seconds">
       <action class="org.jbpm.websale.RemindActor">
       <swimlaneName>salesman</swimlaneName>
       </action>
       </timer>
       ...
       </task>
       ...
       </task-node>
       ...
      


      pros: xml parsing availability. still somewhat verbose.
      cons: xml-java mapping is not trivial. current IDE's have no out of the box refactoring capabilities. hard to integrate with IDE refactoring.

      3) A third approach is a custom language. The example shows a custom language which is inspired by the java syntax but it could very well be completely different.

      public process Order {
      
       startNode(StartState) {
       --->(sendQuote);
       }
      
       sendQuote(Node) {
       --approve-->(ship);
       --reject-->(cancelled);
       }
      
       ship(Node) {
       --->(completed)
       }
      
       completed(EndState) {
       }
      
       cancelled(EndState) {
       }
      
       // process variables
       Customer customer;
       String item;
      
       public void thisCouldBeAnActionHandlerMethod() {
       // java executed in the middle of a process
       }
      }
      


      pros: very readable.
      cons: custom parser needs to be written. IDE integration will be hard. no base language to fall back upon, so probably no IDE frameworks will be reusable. hard to integrate with IDE refactoring.

      4) Process declaration embedded in Java. In this approach, not the whole process graph is created in Java, but just the structure is declared so that the framework can build the object graph from the information in the java class (e.g. by reflection).

      public class Order {
      
       Execution execution;
      
       static final Activities ACTIVITIES = new Activities();
       static class Activities {
       Activity start = new Activity();
       Activity sendQuote = new Activity();
       Activity waitForApproval = new Activity();
       Activity ship = new Activity();
       Activity bill = new Activity();
       Activity end = new Activity();
       {
       // transitions
       start.addTransition(sendQuote);
       sendQuote.addTransition(waitForApproval);
       waitForApproval.addTransition(ship);
       waitForApproval.addTransition(bill);
       ship.addTransition(end);
       bill.addTransition(end);
       }
       }
      
       public static Swimlanes SWIMLANES = new Swimlanes();
       static class Swimlanes {
       Swimlane initiator = new Swimlane();
       }
      
       public static Tasks TASKS = new Tasks();
       static class Tasks {
       Task doLaundry = new Task();
       };
      
       /**
       * process variables
       */
       Customer customer;
       String product;
      
       /**
       * an external trigger to create a new order process.
       */
       public Order(Customer c) {
       this.customer = customer;
       execution = new Execution(this);
       }
      
       /**
       * an external trigger that sends the signal approve in the activity waitForApproval.
       */
       @Signal(ACTIVITIES.waitForApproval)
       public void approve() {
       ...
       }
      
       /**
       * this is a custom activity implementation.
       */
       @Activity(sendQuote)
       public void sendQuote() {
       boolean hasSucceeded = send();
       if (hasSucceeded) {
       execution.signal(OK);
       } else {
       execution.signal(NOK);
       }
       }
      }
      


      pros: still very well readable. REFACTORING out of the box.
      cons: hard to put the graphical designer on top of this. there will have to be some coding restrictions in order for the graphical designer tool to recognize and update the java class AST that represents the process graph.