Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Ode Wiki" for change 
notification.

The following page has been changed by MatthieuRiou:
http://wiki.apache.org/ode/Jacob

The comment on the change is:
Changing class names to reflect code refactorings.

------------------------------------------------------------------------------
  
  By rolling up these concerns in the framework, the implementation of the BPEL 
constructs can be simpler by limiting itself to implementing the BPEL logic and 
not the infrastructure necessary to support it.
  
- The approach we'll take in this tutorial is looking at the [#rational] of 
Jacob and its [#concepts] first. Then we'll illustrate with one complete 
[#examples example] (more coming...). But if you're a reverse reader, you can 
also decide to start with the [#example1 example].
+ The approach we'll take in this tutorial is looking at the [#rational] of 
Jacob and its [#concepts] first. Then we'll illustrate with one complete 
[#examples example]. But if you're a reverse reader, you can also decide to 
start with the [#example1 example].
  
  [[Anchor(rational)]]
  = Rationale behind the model =
@@ -165, +165 @@

    OSequence def;
    CompletionChannel myCompletionChannel;
    ...
-   void self() {
+   void run() {
      // Start of by instantiating a sequential child runner for the first
      // (0th) child...
      instance(new SequenceChildRunner(0))
@@ -174, +174 @@

    class SequenceChildRunner {
      int currentchild;
      SequenceChildRunner(int childNumber) { currentchild = childNumber; }
-     void self() {
+     void run() {
         if(currentChild == def.children.size()) {
           // We are past the last child, the sequence is done.
           myCompletionChannel.completed();
@@ -214, +214 @@

    CompletionChannel myCompletionChannel;
     
    ...
-   void self() {
+   void run() {
       // Create a channel for an externally managed alarm.
       TimerChannel timerChannel = newChannel(TimerChannel.class);
       // register the alarm with the runtime.
@@ -241, +241 @@

  
  As briefly demonstrated above, channels are interfaces used for communication 
between activities in PXE engine. There are several types of channels like 
!TerminationChannel, !ParentScopeChannel or !CompensationChannel (their 
respective purpose should be obvious from their name). Some basic channels are 
provided to all activities when they're created to allow them to interact with 
their environment. When an activity wants to notifies its parent that it has 
terminated for example, it just calls its parent !TerminationChannel (see the 
Empty example above).
  
- Don't look for channels implementations because there are none. Channels 
implementation is provided through a dynamic proxy (see 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/vpu/ChannelFactory.java
 ChannelFactory].createChannel() and 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/vpu/ChannelFactory.java
 ChannelFactory].!ChannelInvocationHandler for more). That's one of the levels 
of decoupling between invocation and actual execution in Jacob.
+ Don't look for channels implementations because there are none. Channels 
implementation is provided through a dynamic proxy (see 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ChannelFactory.java
 ChannelFactory].createChannel() and 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ChannelFactory.java
 ChannelFactory].!ChannelInvocationHandler for more). That's one of the levels 
of decoupling between invocation and actual execution in Jacob.
  
- == JavaClosure / Abstraction ==
+ == JacobObject / JacobRunnable ==
  
- If you don't care much about the details, the bottom line is: a 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/JavaClosure.java
 JavaClosure] and an 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/Abstraction.java
 Abstraction] are just a method implementation. This metod gets executed when 
the abstraction is executed.
+ If you don't care much about the details, the bottom line is: a 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobObject.java
 JacobObject] and an 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobRunnable.java
 JacobRunnable] are just a method implementation. This method gets executed 
when the abstraction is executed.
  
- From Wikipedia: "A closure combines the code of a function with a special 
lexical environment bound to that function (scope). Closure lexical variables 
differ from global variables in that they do not occupy the global variable 
namespace. They differ from object oriented object variables in that they are 
bound to functions, not objects.". Normally closures aren't supported in Java 
so 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/JavaClosure.java
 JavaClosure] tries to feel that gap. But it's not a true closure anyway, which 
makes thing easier. Closures in Jacob are statically coded, whereas in most 
languages supporting closures these are dynamic. So basically in Jacob, a 
closure is expected to implement some methods and provides other utility 
methods to manipulate channels and replicate itself.
+ A JacobObject is meant to be a closure. From Wikipedia: "A closure combines 
the code of a function with a special lexical environment bound to that 
function (scope). Closure lexical variables differ from global variables in 
that they do not occupy the global variable namespace. They differ from object 
oriented object variables in that they are bound to functions, not objects.". 
Normally closures aren't supported in Java so 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobObject.java
 JacobObject] tries to feel that gap. But it's not a true closure anyway, which 
makes thing easier. Closures in Jacob are statically coded, whereas in most 
languages supporting closures these are dynamic. So basically in Jacob, a 
closure is expected to implement some methods and provides other utility 
methods to manipulate channels and replicate itself.
  
- 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/Abstraction.java
 Abstraction] is just a closure that requires the implementation of only one 
method: self(). As ''all activities inherit from 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/Abstraction.java
 Abstraction]'' they're all supposed to implement their main processing in this 
self() method. Their initialization occur in their respective constructors.
+ 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobRunnable.java
 JacobRunnable] is just a JacobObject that requires the implementation of only 
one method: run(). As ''all activities inherit from 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobRunnable.javJacobRunnableable]''
 they're all supposed to implement their main processing in this run() method. 
Their initialization occur in their respective constructors.
  
  == Method Lists (MLs) ==
  
  ML classes can be seen as the other end of a channel. Only they're not 
invoked directly when one calls a channel method, but only once the Jacob 
engine has popped the channel invocation from its internal stack (again you can 
see how the execution stack gets broken here).
  
- Usually MLs implementations in PXE are inlined because it's just easier to 
declare them in the activities self() method. For example if you look at the 
Sequence example shown above you'll see something like:
+ Usually MLs implementations in PXE are inlined because it's just easier to 
declare them in the activities run() method. For example if you look at the 
Sequence example shown above you'll see something like:
  
  {{{#!java
-     void self() {
+     void run() {
        ...
           // create an object to wait for the "completed()" notification
           // from the child activity.
@@ -273, +273 @@

      }
  }}}
  
- The object method here is inherited from !JavaClosure and is just a way to 
hand our ML to Jacob. So that the Jacob runtime can match it with an incoming 
channel message later on.
+ The object method here is inherited from !JacobObject and is just a way to 
hand our ML to Jacob. So that the Jacob runtime can match it with an incoming 
channel message later on.
  
- == VPU and Soup ==
+ == VPU and ExecutionQueue ==
  
- The 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/vpu/JacobVPU.java
 VPU] is where all the Jacob processing is occuring. When a !JavaClosure is 
injected inside the VPU, it's actually registered as a 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/soup/Reaction.java
 Reaction], which is just wrapping the closure with the method to call on the 
closure to execute it (in our case always the self() method as we're only 
dealing with Abstraction instances).
+ The 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/JacobVPU.java
 VPU] is where all the Jacob processing is occuring. When a !JacobObject is 
injected inside the VPU, it's actually registered as a 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/soup/Continuation.java
 Continuation], which is just wrapping the JacobObject with the method to call 
on the JacobObject to execute it (in our case always the run() method as we're 
only dealing with JacobRunnable instances).
  
- The 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/soup/Soup.java
 Soup] (and its implementation 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/vpu/FastSoupImpl.java
 FastSoupImpl]) is just a container for all the artifacts managed by the VPU 
(mostly channels and reactions) to organize them in queues where artifacts can 
be pushed and popped. It also records some execution statistics.
+ The 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/soup/ExecutionQueue.java
 ExecutionQueue] (and its implementation 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/FastExecutionQueueImpl.java
 FastExecutionQueueImpl]) is just a container for all the artifacts managed by 
the VPU (mostly channels and reactions) to organize them in queues where 
artifacts can be pushed and popped. It also records some execution statistics.
  
- So the VPU main processing is just dequeuing a reaction from the soup and 
executing it by calling its abstraction's self() method (remember that the 
reaction just wraps an abstraction). That's all (check 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/jacob/src/main/java/com/fs/jacob/vpu/JacobVPU.java
 JacobVPU].execute(), you'll see that I'm not lying). However when the 
Abstraction (usually an activity) gets executed the following things can happen:
+ So the VPU main processing is just dequeuing a reaction from the soup and 
executing it by calling its abstraction's run() method (remember that the 
reaction just wraps an abstraction). That's all (check 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/JacobVPU.java
 JacobVPU].execute(), you'll see that I'm not lying). However when the 
JacobRunnable (usually an activity) gets executed the following things can 
happen:
  
  * if other abstractions (usually other activities) are created, they will be 
appended to the reaction queue,
  * if new channels are created, they will be saved for later usage,
  * if channels are invoked, the message will be saved to match against a new 
ML,
  * if a new ML instance is created, it will be submitted to the VPU that will 
try to match it against a channel invocation.
  
- The VPU is also responsible for persisting its internal state. So when an 
execution stops (for example our process has reach a receive) the VPU state is 
serialized and saved for later reuse. This logic can be seen in 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/RuntimeContextImpl
 RuntimeContextImpl].execute().
+ The VPU is also responsible for persisting its internal state. So when an 
execution stops (for example our process has reach a receive) the VPU state is 
serialized and saved for later reuse. This logic can be seen in 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/RuntimeContextImpl
 RuntimeContextImpl].execute().
  
- There's one more thing that should be mentioned here. Reactions (and hence 
Abstractions) don't "stay" in the VPU queues. They just get popped, executed 
and that's it. So if an abstraction must last more than one execution, it 
should simply fork itself. This explains why in our Sequence example already 
pasted above we see the line:
+ There's one more thing that should be mentioned here. Continuations (and 
hence JacobRunnables) don't "stay" in the VPU queues. They just get popped, 
executed and that's it. So if an abstraction must last more than one execution, 
it should simply fork itself. This explains why in our Sequence example already 
pasted above we see the line:
  
  {{{#!java
     instance(new SequenceChildRunner(currentChild+1));
@@ -348, +348 @@

  </process>
  }}}
  
- Everything starts with a receive. So our entry point here in our 
Jacob-focused discussion is going to be 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/BpelProcess.java
 BpelProcess].PartnerLinkMyRoleImpl.inputMsgRcvd(). The code that matters to us 
now is the following (executed when a message is targeted at a createInstance 
receive):
+ Everything starts with a receive. So our entry point here in our 
Jacob-focused discussion is going to be 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/BpelProcess.java
 BpelProcess].PartnerLinkMyRoleImpl.inputMsgRcvd(). The code that matters to us 
now is the following (executed when a message is targeted at a createInstance 
receive):
  
  {{{#!java
      BpelRuntimeContextImpl instance = createRuntimeContext(newInstance, new 
PROCESS(_oprocess), messageExchange);
@@ -365, +365 @@

      }
  }}}
  
- The process itself get injected. When executed, 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/PROCESS.java
 PROCESS] just instantiates a scope to control the execution of its child 
activity and starts listening on compensation and completion channel. From the 
process we go to a scope, then our main sequence and finally our receive.
+ The process itself get injected. When executed, 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/PROCESS.java
 PROCESS] just instantiates a scope to control the execution of its child 
activity and starts listening on compensation and completion channel. From the 
process we go to a scope, then our main sequence and finally our receive.
  
- Receives are just mapped to a pick onMessage so its Jacob implementation 
should be looked for in 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/PICK.java
 PICK]. The 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/PICK.java
 PICK] is just about isolating the right correlations and selecting a message 
for it, then waiting for the message. In our createInstance case we'll be more 
interested in the following code, located in 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/BpelRuntimeContextImpl.java
 BpelRuntimeContextImpl].select() (and called by PICK):
+ Receives are just mapped to a pick onMessage so its Jacob implementation 
should be looked for in 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/PICK.java
 PICK]. The 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/PICK.java
 PICK] is just about isolating the right correlations and selecting a message 
for it, then waiting for the message. In our createInstance case we'll be more 
interested in the following code, located in 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/BpelRuntimeContextImpl.java
 BpelRuntimeContextImpl].select() (and called by PICK):
  
  {{{#!java
      if (_instantiatingMessageExchange != null && _dao.getState() == 
ProcessState.STATE_READY) {
@@ -384, +384 @@

  Which just happens to call something like:
  
  {{{#!java
-     vpu.inject(new Abstraction() {
+     vpu.inject(new JacobRunnable() {
-         public void self() {
+         public void run() {
              PickResponseChannel responseChannel = 
importChannel(responsechannel, PickResponseChannel.class);
              responseChannel.onRequestRcvd(idx, mex);
          }
      });
  }}}
  
- That's where things really start. When injected, this abstraction just calls 
the response channel for our receive. The other side of this channel is 
implemented as a ML in the 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/PICK.java
 PICK]:
+ That's where things really start. When injected, this abstraction just calls 
the response channel for our receive. The other side of this channel is 
implemented as a ML in the 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/PICK.java
 PICK]:
  
  {{{#!java
      object(false, new PickResponseML(_pickResponseChannel) {
@@ -412, +412 @@

  
  The parent sequence gets notified almost immediately after the 
onRequestRcvd() methods finishes.
  
- Now how does our sequence gets the control back? Well, once again, let's look 
at the ML, the other side of the channel. As one of the most important job of 
the VPU is matching channels invocations and MLs, we'll get to the 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/SEQUENCE.java
 sequence] by its !ParentScopeML implementation:
+ Now how does our sequence gets the control back? Well, once again, let's look 
at the ML, the other side of the channel. As one of the most important job of 
the VPU is matching channels invocations and MLs, we'll get to the 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/SEQUENCE.java
 sequence] by its !ParentScopeML implementation:
  
  {{{#!java
  class SEQUENCE extends ACTIVITY {
    ...
-   private class ACTIVE extends BpelAbstraction {
+   private class ACTIVE extends BpelJacobRunnable {
      ....
-     public void self() {
+     public void run() {
        ...
        object(new ParentScopeML(_child.parent) {
          public void compensate(OScope scope, SynchChannel ret) {
@@ -445, +445 @@

  }
  }}}
  
- The method that will get executed is of course the completed() method. It 
simply completes if a fault has been thrown, a termination has been requested 
and if no child activities remain. Being of an optimistic nature, we'll check 
what happens when everything goes just fine. In this second case a remaining 
activity is removed and the 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/SEQUENCE.java
 SEQUENCE] abstraction itself is reinstantiated. Which leads us to what the 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/SEQUENCE.java
 SEQUENCE] does:
+ The method that will get executed is of course the completed() method. It 
simply completes if a fault has been thrown, a termination has been requested 
and if no child activities remain. Being of an optimistic nature, we'll check 
what happens when everything goes just fine. In this second case a remaining 
activity is removed and the 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/SEQUENCE.java
 SEQUENCE] abstraction itself is reinstantiated. Which leads us to what the 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/SEQUENCE.java
 SEQUENCE] does:
  
  {{{#!java
-   public void self() {
+   public void run() {
      final ActivityInfo child = new  ActivityInfo(genMonotonic(),
              _remaining.get(0),
              newChannel(TerminationChannel.class), 
newChannel(ParentScopeChannel.class));
@@ -459, +459 @@

  
  As you can see, it just instantiates the next child abstraction and also 
another abstraction named ACTIVE. So what's this ACTIVE that we've already seen 
a bit before? Well, it's just the abstraction that keeps on following child 
activities when they execute. It's more like a convention on all 
containment-based activity in PXE (while, sequence, pick, ...) that the main 
activity abstraction just kicks off the processing. Then an ACTIVE (also 
sometimes called WAITER) abstraction takes care of following the children.
  
- Continuing to the next step, we've just instantiated an abstraction for the 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/WHILE.java
 while] in our example process, as it's the next child of the sequence. So what 
happens there?
+ Continuing to the next step, we've just instantiated an abstraction for the 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/WHILE.java
 while] in our example process, as it's the next child of the sequence. So what 
happens there?
  
  {{{#!java
-   public void self() {
+   public void run() {
      boolean condResult = false;
      try {
        condResult = checkCondition();
@@ -482, +482 @@

    }
  }}}
  
- Now you should be getting more familiar with that sort of code. First step is 
evaluating the 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/WHILE.java
 while] condition. If it turns out it's true, then a child abstraction gets 
created as well as a WAITER to follow its execution. The WAITER implementation 
is again pretty straightforward:
+ Now you should be getting more familiar with that sort of code. First step is 
evaluating the 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/WHILE.java
 while] condition. If it turns out it's true, then a child abstraction gets 
created as well as a WAITER to follow its execution. The WAITER implementation 
is again pretty straightforward:
  
  {{{#!java
-   private class WAITER extends BpelAbstraction {
+   private class WAITER extends BpelJacobRunnable {
      private ActivityInfo _child;
      private boolean _terminated;
  
@@ -493, +493 @@

        _child = child;
      }
  
-     public void self() {
+     public void run() {
        object(false, new TerminationML(_self.self) {
          public void terminate() {
            _terminated = true;
@@ -517, +517 @@

    }
  }}}
  
- Termination and compensation aren't doing anything really interesting. 
Completion, just like for the sequence, re-instantiates the 
[http://svn.apache.org/repos/asf/incubator/ode/scratch/pxe/bpel-runtime/src/main/java/com/fs/pxe/bpel/runtime/WHILE.java
 WHILE] abstraction. And that's how we get our loop, by re-instantiating the 
main WHILE abstraction (again evaluating the condition and creating a child if 
it's true).
+ Termination and compensation aren't doing anything really interesting. 
Completion, just like for the sequence, re-instantiates the 
[http://svn.apache.org/repos/asf/incubator/ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/WHILE.java
 WHILE] abstraction. And that's how we get our loop, by re-instantiating the 
main WHILE abstraction (again evaluating the condition and creating a child if 
it's true).
  
  Finally, when the while condition becomes false, it notifies its parent 
channel. The sequence then goes to our last activity: reply. As expected, the 
reply replies, just sending the variable content and notifying its parent for 
completion. The sequence has no more children to execute so it also notifies 
its own parent, which is the process. We then just declare the process to be 
completed and that's it! We're done!
  

Reply via email to