Sequence Diagrams

  1. Process instance creation
  2. ProcessContext Initialisation
  3. Dispatching incoming messages
  4. An Example

Process Instance creation

First of all it is necessary that the invoked process has been deployed on bexee in order to be started. A BPEL process can be created when a particular receive activity of a process is called. It must be an activity within the process which is not preceeded by any other activity and which is marked with a "createInstance" property set to "true". Not in all cases calling such a receive activity will result in the creation of a process. Processes with multiple start activities or processes that need more than one user interaction to complete might have already been created. This will be considered as a separate case.

Glossary: In the following sections the BPEL processes will be called processes for short. The information related to a process instance, will be encapsulated within a process context. In the concrete implementationthe process its context will be encapsulated in a container object called process instance.

As to explain how bexee creates new processes we will consider the following case:

A process has been deployed and the process has not yet been created by another receive activity. Then a receive activity is called.

The bexee engine receives a call for a receive activity, which is represented as a message. A bexee provider (aka. Axis pivot handler or provider) creates a new dispatcher with the given message. The dispatcher finds the process and a process instance given the the passed-in message. It also let creates a new process controller, which will be responsible for executing the process. After the creation of the dispatcher, the provider calls the dispatcher's dispatch() method. As a result of this method, the dispatcher dispatches the message to the process controller in a new thread. Depending whether the process is synchronous or asynchronous, the dispatcher will either wait for the process controller to terminate and return a result or return directly back to the client that sent the message. Either way the it will cause the process controller to execute the process. The controller will then traverse the activities of the process and execute them. This procedure is represented in the following sequence diagram:

Sequence Diagram

Process context creation and initiation will be described in the following section.

ProcessContext Initialisation

When an incoming Message for a receive activity arrives, the engine has to decide, whether a new instance of a process has to be created or whether the message has to be passed to an existing process instance. This decision is made based on the process specific correlation data. In case it is not possible to correlate the arriving message to an existing process instance, a new process instance has to be created. The dispatcher will create a new process instance, find the right BPEL process and associate a new empty process context with it. Such a process instance will be passed to the process controller together with the message. After the creation of a new process context, the ProcessController will initiate the process instance, i.e. the partner links, partners, variables, correlation sets, fault handlers, compensation handlers and the event handlers. After the initiation, the ProcessController passes the received BexeeMessage throught the process util it reaches the correspondent first receive activity . The activity then consumes the call represented as a message. After processing the receive activity, the following activities are processed until a next receive activity is processed. The processing doesn't continue there because the receive call message has been consumed by the last receive. The processing returns to the process controller and waits then for a next receive call.

initiateProcess.gif

Dispatching incoming messages

This section describes in further detail how exactly an incoming message is dispatched to the ProcessController.

Asynchronous request/response

We will first consider the easier case, where a message arrives at the engine for processing, but the client doesn't need the answer right away. Actually it is not the client that makes this decision, but this is specified in the deployed BPEL process, but this shall not be of further importance for what we will try to explain now.

  1. The system creates a new Dispatcher and dispatches the inbound message to it.

  2. The Dispatcher starts the system starts the ProcessController in a new thread.

  3. The Dispatcher either immediately returns control back to the system, possibly by returning an appropriate return message.

  4. At the same time the ProcessController will start to process the arrived message.

  5. Once the ProcessController finishes processing the message, it will either send the result to a call back interface provided by the client or just terminate.

Synchronous request/response

Things get a bit more tricky when a client starts a synchronous BPEL process. This means that the client needs to wait until the processing of the entire BPEL process is done in order to get the response.

As we saw in the preceding section, an incoming message will always be processed in a new thread. The reason of doing this is explained in Processing asynchronous <invoke>s, further down in this section.

For the Dispatcher, this means, that it has to wait until the entire BPEL process has been processed and thus terminated.

  1. The system creates a new Dispatcher and dispatches the inbound message to it.

  2. The Dispatcher starts the system starts the ProcessController in a new thread.

  3. Right after kicking off the ProcessController the Dispatcher acquires a lock on the ProcessContext object. Hence the main thread that started the Dispatcher will be put to sleep.

  4. In the meantime the the ProcessController will start to process the arrived message.

  5. Once the ProcessController finishes processing all the activities in the process, it will store the result of the process execution in the ProcessContext and notify the locking thread.

    It is important to note that there might be further input from the user or other partner services is needed, to fully terminate a given process and that the Dispatcher will not return a result until every activity has been processed and the process terminates.

  6. The Dispatcher will then resume its execution, fetch the result out of the ProcessContext and give it back to the system.

Sequence Diagram

DispatcherThread
synchronized (ctx) {
  try {
      // wait until the process has finished and get the result
      ctx.wait();
      result = ctx.getResult();
  } catch (InterruptedException e) {
      throw new DispatcherException("Dispatcher interrupted", e);
  }
}

public void run() {
    controller.processMessage(instance, message);
}
ProcessContext
public synchronized void setResult(Object result) {
    this.result = result;
    this.notify();
}

Warning Multithreading issues with Mozilla Browsers

Note that there seems to be a serious restriction when using Mozilla browsers: If a web resource is requested that takes a long time to send a response (e.g. a synchronous request that started a long-running BPEL process) it is NOT possible to send a request to that same resource again. It is of course still possible to send a request to other resources on the same server and Tomcat will use a new thread to process the request as expected. But it looks like Mozilla does not send a request to exactly the same resource until a response for the first request has been received.

We came across this issue by using either Mozilla/5.0 rv: 1.7.3 or Mozilla/5.0 rv: 1.6 (Firefox).

Further investigations were not undertaken due to time constraints and the consideration that calling a web service from within a web browser is rather unusual. But nevertheless this is a serious limitations and should definitely be inspected carefully if the project will be continued seriously.

Processing asynchronous <invoke>s

It is possible that a BPEL process doesn't terminate after the first message it received, because it might have to wait for more messages from other sources. This could be the case if an asynchronous <invokes> activity inside a BPEL process is executed. The process will continue it's execution until it reaches a point where further input response is needed, e.g. a <receive> element.

<!--  initiate the remote process -->
<invoke name="invokeAsyncService" partnerLink="AsyncBPELService"
    portType="services:AsyncBPELService"
    operation="initiate" inputVariable="request"/>

<!--  receive the result of the remote process -->
<receive name="receive_invokeAsyncService" partnerLink="AsyncBPELService"
    portType="services:AsyncBPELServiceCallback"
    operation="onResult" variable="response"/>

Message-driven process execution

Because the arriving new message will again trigger process execution (in exactly the same way a new message does) we are confronted with a message-driven model and it is thus not necessary for the ProcessController to wait until a new message arrives. Quite the contrary, the thread that triggered the ProcessController will terminate and if a new message arrives again later, the ProcessController will be triggered again by a new thread to process the message and so on.

This leads to the big advantage that the ProcessController doesn't have to wait at a given activity or remember where it had stopped the last time.

An Example

The following example tries to explain how an incoming request is processed by the ProcessController.

Note that this example doesn't make much sense and is incomplete as parts of the BPEL document such as <partnerLinks> or <variables> are not shown for the sake of the simplicity of this illustration.

Below you'll find an excerpt of a BPEL document and the corresponding sequence diagram.

BPEL excerpt
<process name="bexeeExample">

  <partnerLinks>
    <partnerLink name="client" />
    <partnerLink name="service" />
  </partnerLinks>

  <variables>
    <variable name="input" messageType="tns:ReceiveRequestMessage"/>
    <variable name="response" messageType="tns:ReceiveResultMessage"/>
  </variables>

  <sequence>

    <!-- receive input from requestor -->
    <receive name="receiveInput" partnerLink="client"
             operation="initiate" variable="input"
             createInstance="yes"/>

    <!--  initiate the remote process -->
    <invoke name="asyncInvoke" partnerLink="service"
        portType="services:AsyncBPELService"
        operation="initiate" inputVariable="input"/>

    <!--  receive the result from the invoked service -->
    <reply name="receiveResult" partnerLink="client"
        operation="initiate" variable="response"/>

  </sequence>

</process>
Sequence diagram
          Sequence Diagram