3 Replies Latest reply on Feb 8, 2007 11:16 PM by Alejandro Guizar

    concurrent execution

    Charles Souillard Newbie

      I am trying to implement the BPEL flow statement.

      How is it possible to start many children of a given Node in a concurrent mode (I don't need a "real" paralellism but only a simulation) ?
      Another thing that I don't know is how to make an execution waiting for an event (in a concurrent mode) ?

      I can explain these feature thanks to the following example :


















      In a simplified way, an activity (sequences in this case) could start its execution even if all its target are evaluated. So the above flow will produce a deterministic execution :
      seq4 -> seq1 -> seq2
      As you probably understand, seq1 and seq2 will probably be examined first and we will have to put them in a waiting state. Then when a source corresponding to seq1'starget will be executed, we will have to start seq1 activity...

      This example is a very simple one as source and traget elements are directly under flow's activities but perhaps an execution could be mixed and a first part of seq1 will be executed and then blocked on a target of another branch...

        • 1. Re: concurrent execution
          Charles Souillard Newbie

          I just see that my process is not visible... I will try again :

          <flow>
          <links>
           <link name="four_to_one"/>
           <link name="one_to_two"/>
          </links>
           <sequence name="seq1">
           <target linkName="four_to_one"/>
           <source linkName="one_to_two"/>
           </sequence>
           <sequence name="seq2">
           <target linkName="one_to_two"/>
           </sequence>
           <sequence name="seq4">
           <source linkName="four_to_one"/>
           </sequence>
          </flow>


          • 2. Re: concurrent execution
            Tom Baeyens Master

            each activity in a flow corresponds to a concurrent path of execution (=org.jbpm.pvm.Execution)

            there are basically 2 ways on how to parse bpel flow xml into a pvm object model:

            1) generate a set of nodes that are connected with transitions.

            2) use a flow node with the concurrent activities as composite nodes inside the bpel flow node.

            in both cases, the implementation of the flow should look like this:

            for each concurrent activity, create a new org.jbpm.pvm.Execution make it point to the flow node and and launch it. launching is different in the 2 approaches.

            in the transitions approach, launching is calling execution.takeTransition

            in the composite nodes approach... hmmm need to think on that.

            • 3. Re: concurrent execution
              Alejandro Guizar Master

              In the current implementation, concurrent activities appear as children of the Flow node. For each such activity, Flow creates an Execution, points it to the child activity and launches it. When the child activity completes, it notifies the Flow node. In turn, Flow examines the remaining Executions to determine if any is still active.

              Links are not implemented as transitions. This is because control does not flow through links as it does through transitions. Links are just synchronization points.

              The current implementation regards links as boolean variables. An activity that is the target of one or more links cannot execute until the link is resolved, i.e. the link variable is assigned a value.

              In the absence of links, Charles' example launches three Executions, which proceed separately without synchronization.

              Adding links does not cause an Execution to leave the source and enter the target.
              Links just cause the Execution at the target to wait for another Execution to complete the source.

              When launched, seq1 reads the value of link four_to_one. Because the link is unresolved (i.e. four_to_one is null), seq1 performs no action and returns. In turn, seq2 reads the value of link one_to_two. Again, the link is unresolved, hence seq2 simply returns. Finally seq4 executes (no link is targeted at it), completes and sets the value of four_to_one to true.

              The Execution parked in the target activity, seq1, is notified that link four_to_one has been resolved. Since seq1 has no other links, the Execution performs the behavior of seq1.

              In code, this means something like

              class Flow {
              
              List<Link> links;
              List<Activity> activities;
              
              void execute(Execution execution) {
               for (Link link : links) {
               LinkValue linkValue = new LinkValue(link);
               execution.setVariable(link.getName(), linkValue);
               }
              
               for (Activity activity : actitivites) {
               Execution childExecution = new Execution(execution);
               childExecution.setNode(activity);
               activity.enter(childExecution);
               }
              }
              
              }
              
              class Activity {
              
              List<Link> sourceLinks;
              List<Link> targetLinks;
              Expression joinCondition;
              
              void enter(Execution execution) {
               if (!areTargetLinksResolved(execution))
               return;
               if (joinCondition.evaluate(execution))
               execute(execution);
               else {
               resolveSourceLinks(execution, false);
               leave(execution);
               }
              }
              
              boolean areLinksResolved(Execution execution) {
               boolean resolved = true;
               for (Link link: targetLinks) {
               LinkValue linkValue = execution.getVariable(link.getName());
               linkValue.setTargetExecution(execution);
               if (linkValue.getStatus() == null)
               resolved = false;
               }
               return resolved;
              }
              
              void resolveSourceLinks(Execution execution, boolean status) {
               for (Link link: targetLinks) {
               LinkValue linkValue = execution.getVariable(link.getName());
               linkValue.setStatus(status);
               }
              }
              
              void linkResolved(Execution execution) {
               enter(execution);
              }
              
              abstract void execute(Execution execution);
              /* for a non-blocking activity looks like
              {
               doSpecificStuff();
              
               resolveSourceLinks(execution, true);
               leave(execution);
              }
              */
              
              }
              
              class LinkValue {
              
              Execution targetExecution;
              Boolean status;
              
              void setStatus(boolean status) {
               this.status = Boolean.valueOf(status);
               if (targetExecution != null)
               targetExecution.getNode().linkResolved(targetExecution);
              }
              
              }


              Charles, does this resemble what you had in mind?