Myths on BPEL

June 6, 2006

Like any other new technology, BPEL has its share of miscommunications and misconceptions.

Let’s consider a few of them:

  • BPEL is a human interaction workflow language: FALSE

BPEL is focused on system-to-system interactions.The omission of native language support for human interaction scenarios is being addressed by BPEL4People.

BPEL is better suited for programming in the large, that is, at the inter-module level (i.e. interconnection of modules). This issue is being addressed by BPELJ.

  • BPEL provides a standard visual notation for representing business processes: FALSE

BPEL provides a standard language for specifying and executing business processes, the BPEL specification does not include a standard notation. However, there exists a business process modeling notation (BPMN) to BPEL mapping.

  • BPEL provides process choreography, that is, means of specifying a network of communicating processes: FALSE

BPEL is not WS-CDL! BPEL specifies the interaction between peer business processes, and not among a network of several processes.

  • BPEL is a declarative language, especially so as it is specified in XML: FALSE

BPEL, just like Java, and C/C++, is an imperative language, based upon states, statements, and the usual structured language constructs we are used to, such as if-then-else, switch-case, while, etc. Being specified in XML, does not make it more or less declarative.

  • BPEL allows the modeling of long running processes: TRUE

BPEL provides native support for compensation handling, a very useful feature for modeling undo work needed to guarantee some form of atomicity when locking resources is prohibitive.

  • BPEL allows the modeling of highly concurrent activities: TRUE

BPEL provides native support for concurrent flows and advance synchronization of these flows.

 


Standard Compliance and BPEL TCK

October 24, 2005

Different standard bodies deal differently in respect to verifying compliance to their published specifications.

Sun’s JCP (Java Community Process version 2.1) is very stringent on implementors of its specifications. The specification lead must provide a technology compatibility kit (TCK). The TCK includes tests, tools, and documentation that a implementor must use to verify and prove conformance to the specification. These TCKs usually consist of huge test-beds, containing hundreds of test-cases. The implementor can only promote conformance to a specification after all test-cases have passed with a positive result.

In contrast, OASIS defines a Adoption Service program. Adoption services are a group of services whose aim is to drive adoption of OASIS standards (and OASIS committee drafts) by means of providing conformance, interoperability, or training/personal skill certification programs. Organizations can work together with OASIS to create a referral relationship, which is then used to advertise the certification programs that the organizations provide. Conformance certification programs usually consist of test assertion summary documents, and a testing process.

I did a quick search in the Web and I could not find any single OASIS referred adoption service program for BPEL, version 1.1 or otherwise.
What this means is that currently there is no way of asserting implementation conformance to the OASIS BPEL4WS 1.1 committee draft.
In another words, even if the implementors wanted to guarantee that their implementation is portable and fully compliant, there is no obvious way of doing so.

In spite of this, there are several vendors that do offer BPEL engine implementations. Wikipedia alone lists over 20 providers. How many of these are really full-fledged BPEL engines? Actually, how many of these even provide a minimum level of portability and QoS? It is very hard to tell.

Even worse, currently the onus of ascertaining conformance is on the client. And vendors are not facilitating it. Vendors do not provide a compatibility issue list, or even document the features that they support.

To confirm this, I wrote two scenarios that test significant but hidden BPEL features and executed these scenarios in a couple of commercial and open-source implementations. The BPEL processes for these scenarios are included for reference.

The first one has to do with isolated scopes. When a scope is marked as isolated (variableAccessSerialized), access to its variables must follow a serialization schedule, so that data consistency is preserved. To force the engine into yielding while running within a isolated scope, I used a receive activity and delayed the dispatch of its message.

The second scenario has to do with dead-path-elimination. Paths that will not (ever) be executed, e.g. the unselected case of a switch statement, must be considered as having a negative link status and this negative status must be propagated to all of its target links. Otherwise the flow may just block indefinitely, or until the transaction, if present, times-out.

None of the implementations I tried were able to cope with either of these scenarios. I was not particularly surprised about this. Granted, the BPEL 1.1 specification is not very clear in respect to these particular features, but they are very important nonetheless. So it seems there is a urgent need for a BPEL TCK!

  1. Isolated scope test-case:
  2. <process name=”isolatedscope” targetNamespace=”http://bea.com/bpeltck/isolatedscope&#8221;
    xmlns=”http://schemas.xmlsoap.org/ws/2003/03/business-process/&#8221;
    xmlns:bpws=”http://schemas.xmlsoap.org/ws/2003/03/business-process/&#8221;
    xmlns:ns1=”http://www.w3.org/2001/XMLSchema&#8221;
    xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221;
    xmlns:client=”http://bea.com/bpeltck/isolatedscope”&gt;

      <partnerLinks>
        <partnerLink name=”client”
    partnerLinkType=”client:plt” myRole=”Provider”/>
      </partnerLinks>
      <variables>
        <variable name=”inputVariable” messageType=”client:RequestMessage”/>
        <variable name=”outputVariable” messageType=”client:ResponseMessage”/>
        <variable name=”totalVar” type=”ns1:string”/>
      </variables>
      <sequence>
        <receive partnerLink=”client” portType=”client:pt” operation=”process” variable=”inputVariable” createInstance=”yes”/>
        <assign >
          <copy>
            <from variable=”inputVariable” part=”payload” query=”/client:ProcessRequest/client:input”/>
            <to variable=”totalVar”/>
          </copy>
        </assign>
        <flow suppressJoinFailure=”yes”>
          <links>
            <link name=”AtoB”/>
          </links>
          <sequence >
            <scope name=”debit” variableAccessSerializable=”yes”>
              <target linkName=”AtoB”/>
              <variables>
                <variable name=”tempVar” type=”ns1:string”/>
              </variables>
              <sequence>
                <assig >
                  <copy>
                    <from variable=”totalVar”/>
                    <to variable=”tempVar”/>
                  </copy>
                </assign>
                <assign>
                  <copy>
                    <from expression=”bpws:getVariableData ( ‘tempVar’ ) – 10″/>
                    <to variable=”totalVar”/>
                  </copy>
                </assign>
              </sequence>
            </scope>
          </sequence>
          <sequence>
            <scope name=”credit” variableAccessSerializable=”yes”>
              <variables>
                <variable name=”tempVar” type=”ns1:string”/>
              </variables>
              <sequence>
                <assign>
                  <source linkName=”AtoB”/>
                  <copy>
                    <from variable=”totalVar”/>
                    <to variable=”tempVar”/>
                  </copy>
                </assign>
                <receive createInstance=”no” partnerLink=”client” portType=”client:pt” operation=”wake” variable=”inputVariable”/>
                <assign>
                  <copy>
                    <from expression=”bpws:getVariableData ( ‘tempVar’ ) + 10″/>
                    <to variable=”totalVar”/>
                  </copy>
                </assign>
              </sequence>
            </scope>
          </sequence>
        </flow>
        <assign>
          <copy>
            <from variable=”totalVar”/>
            <to variable=”outputVariable” part=”payload” query=”/client:ProcessResponse/client:result”/>
          </copy>
        </assign>
        <reply name=”replyOutput” partnerLink=”client” portType=”client:pt” operation=”process” variable=”outputVariable”/>
      </sequence>
    </process>

  3. DPE test-case:
  4. <process name=”dpe” targetNamespace=”http://bea.com/bpeltck/dpe&#8221;
    xmlns=”http://schemas.xmlsoap.org/ws/2003/03/business-process/&#8221;
    xmlns:bpws=”http://schemas.xmlsoap.org/ws/2003/03/business-process/&#8221;
    xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221;
    xmlns:client=”http://bea.com/bpeltck/dpe&#8221; >

      <partnerLinks>
        <partnerLink name=”client” partnerLinkType=”client:plt” myRole=”Provider” partnerRole=”Requester”/>
      </partnerLinks>
      <variables>
        <variable name=”inputVariable” messageType=”client:RequestMessage”/>
        <variable name=”outputVariable” messageType=”client:ResponseMessage”/>
      </variables>
    <sequence>
        <receive partnerLink=”client” portType=”client:pt” operation=”initiate” variable=”inputVariable” createInstance=”yes”/>
        <flow suppressJoinFailure=”yes”>
          <links>
            <link name=”AtoB”/>
          </links>
          <sequence>
            <target linkName=”AtoB”/>
            <assign>
              <copy>
                <from variable=”inputVariable” part=”payload” query=”/client:ProcessRequest/client:input”/>
                <to variable=”outputVariable” part=”payload” query=”/client:ProcessResponse/client:result”/>
              </copy>
            </assign>
          </sequence>
          <sequence>
            <switch>
              <case condition=”bpws:getVariableData ( ‘inputVariable’, ‘payload’, ‘/client:ProcessRequest/client:input’ ) = ‘donotmatch'”>
                <empty>
                  <source linkName=”AtoB”/>
                </empty>
              </case>
              <otherwise> <!– selected case –>
                <sequence >
                  <assign>
                    <copy>
                      <from expression=”‘otherwise'”/>
                      <to variable=”outputVariable” part=”payload” query=”/client:ProcessResponse/client:result”/>
                    </copy>
                  </assign>
                </sequence>
              </otherwise>
            </switch>
          </sequence>
        </flow>
        <invoke partnerLink=”client” portType=”client:cb” operation=”onCallback” inputVariable=”outputVariable”/>
      </sequence>
    </process>


What problems does BPEL help to solve?

September 9, 2005

There has been a lot of talk about BPEL, but mostly it is being focused on its technical features, such as how compensation handling works.

Particularly, I have not seen a lot of emphasis on the use-cases that BPEL helps to solve.

So, as an attempt to understand where one can use BPEL (in the context of integration) and what are the most valuable BPEL features, I’ve tried to come up with a (incomplete) list of scenarios where BPEL is able to help with:

  • Intelligent dynamic routing based upon message content and process state;
  • Compensation of non-transactional work and long-running processes;
  • Sequential and concurrent splitter and aggregation of messages;
  • Content enrichment and message filtering;
  • Support for process instances with complex exception/fault paths;
  • Support for process instances with multiple on-going conversations;

I would be very interested in knowing if anyone else has had experience implementing integration scenarios using BPEL. What were you trying to solve? What was easy to do and what was hard to do? How was it better (or worse) than using some other technology, such as XSLT?


WEB SERVICES MESSAGES FOR BPEL, JBI, AND JAX-RPC

September 7, 2005

It is interesting how applications differ when modeling WSDL messages.

WS-BPEL 2.0:

For instance, BPEL 2.0 represents a WSDL (1.1) message by conceptually materializing each WSDL message part into a separate Xml document. In this case, the document element corresponds to either a synthesized element whose type is equal to the part's type attribute, or the document element is the element referenced by the part's element attribute itself (in summary).

For example, consider the following WSDL definition:

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
    targetNamespace="urn:sample" 
    xmlns:tns="urn:sample"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" >

    <types>
        <xsd:schema targetNamespace="urn:sample">
            <xsd:element name="value" type="xsd:string" />
        </xsd:schema>
    </types>

    <message name="sampleMessage">
        <part name="part1" type="xsd:string" />
        <part name="part2" element="tns:value" />
    </message>
</definitions>

Note that we are not worried about a particular binding in the context of this scenario. For example, a SOAP literal binding would only allow messages to have one part if it uses the type attribute.

One example of a message instance for this definition is the following set of two document instances:

<ns2:message xmlns:ns2="http://com.bea.sample.bpelmessage">first value!</ns2:message>

and

<ns1:value xmlns:ns1="urn:sample">second value!</ns1:value>

JBI:

As for JBI, WSDL (1.1) messages are materialized into a single Xml document whose document element ‘wraps’ each message part as a child element.

So, for the previous WSDL definition, one example of a message instance is:

<jbi:message version="1.0" type="ns1:sampleMessage"
    xmlns:ns1="urn:sample" xmlns:jbi="...">
    <jbi:part>first value!</jbi:part>
    <jbi:part>
        <ns1:value>second value!</ns1:value>
    </jbi:part>
</jbi:message>

JAXRPC 2.0:

JAXRPC approach is slightly different, as JAXRPC binds the WSDL message to Java instead of representing it in a Xml document. Still, it’s approach is somewhat similar to that of BPEL, as it binds each WSDL message part into a separate Java method argument.

In this case, lets consider a slightly modification of the previous WSDL definition, which is more appropriate for RPC:

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
    targetNamespace="urn:sample" 
    xmlns:tns="urn:sample"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <types>
        <xsd:schema targetNamespace="urn:sample">
            <xsd:element name="value1" type="xsd:string" />
            <xsd:element name="value2" type="xsd:string" />
        </xsd:schema>
    </types>

    <message name="sampleMessage">
        <part name="part1" element="tns:value1" />
        <part name="part2" element="tns:value2" />
    </message>

    <portType name="samplePT">
        <operation name="sampleOper">
            <input message="tns:sampleMessage" />
        </operation>
    </portType>
</definitions>

The corresponding Java binding would be:

void sampleOper(java.lang.String part1, java.lang.String part2)
    throws RemoteException

WSDL 2.0:

Finally, WSDL 2.0 solves this problem by getting rid of the WSDL message part concept and hence specifying WSDL messages using W3C Schema element, which already has a obvious mapping when materialized into a document instance.

Conclusion:

The result of these differences is that one would have to transform/adapt the same WSDL (1.1) message when routing it within a JBI implementation through a BPEL service engine, JAXRPC applications, etc.