Thursday, November 12, 2009

From ESB to BPEL - Continuing with the RiftSaw-JBossESB Integration

In the previous post to this blog, we looked at orchestrating JBossESB services from a RiftSaw BPEL process. In this post, we'll look at the other side of the RiftSaw-JBossESB integration; invoking a RiftSaw BPEL process from an ESB service.

Invoking a RiftSaw BPEL Process - From the JBossESB's Perspective, it's a Web Service

There are a couple of ways to do this. Remember, that from the JBossESB's perspective, a RiftSaw BPEL process is a web service. This means that a JBossESB service action can invoke a BPEL process in the same way that it can invoke any other web service that exposes a WSDL definition. There are multiple examples of this approach illustrated in the JBossESB quickstarts. For example, in the "webservice_consumer1" quickstart, the action used to invoke a web service is defined as:

In jboss-esb.xml:

<actions mep="OneWay">
<action name="request-mapper"
class="org.jboss.soa.esb.samples.quickstart.webservice_consumer1.MyRequestAction">
</action>
<action name="soapui-client-action"
class="org.jboss.soa.esb.actions.soap.SOAPClient">
<property name="wsdl"
value="http://127.0.0.1:8080/Quickstart_webservice_consumer1/HelloWorldWS?wsdl"/>
<property name="responseAsOgnlMap" value="true" />
<property name="SOAPAction" value="sayHello"/>
</action>
<action name="response-mapper"
class="org.jboss.soa.esb.samples.quickstart.webservice_consumer1.MyResponseAction">
</action>
<action name="testStore" class=
"org.jboss.soa.esb.actions.TestMessageStore"/>
</actions>
  • Line 6: The SOAPClient class makes the call to the webservice.
  • Line 9: The parameter responseAsOgnlMap tells the JBossESB move the SOAP reponse data into that OGNL-based map and attach it to the message.
  • Line 10: The reference to the method to be invoked in the web service.
OK. That was easy. We completed the cycle of orchestrating JBossESB services from a RiftSaw BPEL process and invoking JBossESB service actions from a RiftSaw BPEL process.

But wait! We're not done yet. The RiftSaw-JBossESB integration also supports another way to invoke JBossESB service actions from a RiftSaw BPEL process without using HTTP, web services and WSDL.

A Different Way - the BPELInvoke Action

One of the JBossESB's features is an extensive set of predefined ("out of the box") actions that can be incorporated into your applications. These actions support a wide variety of tasks including:
  • Transformers and Converters - converting message data from one form to another
  • Business Process Management - integrating with JBoss jBPM
  • Scripting - automating tasks in supported scripting languages
  • Services - integration with EJBs
  • Routing - moving message data to the correct services
  • Notifier - sending data to ESB unaware destinations
  • Webservices/SOAP - the name says it all - support for Webservices
(There's also a Miscellaneous group that includes only one action - org.jboss.soa.esb.actions.SystemPrintln. This action prints of a message.)

JBossESB also supports a new out-of-the-box action that can be used to directly invoke a RiftSaw BPEL process. This action (org.jboss.soa.esb.actions.bpel.BPELInvoke) can be used if RiftSaw is installed and running in the same Java VM as the JBossESB and if the target BPEL process is deployed to the local RiftSaw instance. If your configuration meets these requirements, then it can be simpler to use the BPELInvoke action. You should also see better performance than using web services, as the RiftSaw BPEL process and JBossESB service actions are running in the same JVM.

The BPELInvoke action enables you to specify not just the RiftSaw process to be invoked, but also the specific operation within that process. You configure the BPELInvoke action with these properties:
  • service - This mandatory property references the service name, as defined in the WSDL, for the target RiftSaw BPEL process.
  • operation - The name says it all. This mandatory property references the operation, also defined in the target Riftsaw BPEL process WSDL, to be invoked.
  • requestPartName - This property defines the WSDL message part that the message content for the JBossESB-aware message processed by the JBossESB action should be mapped to. This property is optional and is used when the incoming JBossESB message does not already represent a multi-part message.
  • responsePartName - And finally, this property is used to extract the content of a response multi-part WSDL message, and insert it into the JBossESB-aware message that is passed to the next JBossESB action in the action pipeline. This property is optional and if it is not defined, the complete multi-part message value will be used in the JBossESB-aware message.
The BPELInvoke action can handle incoming messages with two types of content:
  • Document Object Model - If the content in the incoming message is a DOM document or element, then it can be used as the complete multi-part message, or as the content of a message part as defined with the optional requestPartName action property. If, however, the message content is a DOM text node, then it can only be used if a multi-part name has been defined in the optional requestPartName action property.
  • Java String - If the content in the incoming message is a string representation of an XML document, then the requestPartName property is optional. If this property is not defined, then the document must represent the complete multipart message. If, however, the message content is a string that does not represent an XML document, then the requestPartName is not optional and must be specified.
Let's take a look at the BPELInvoke action in action by running a quickstart example program.

BPELInvoke in a Quickstart

I can't say it often enough; the quickstarts are a great resource for learning how JBoss products work, and as a starting point for developing your own code. The BPELInvoke action is used in the "bpel_helloworld" quickstart. This quickstart is installed into your JBossESB server's /samples/quickstarts directory as part of the RiftSaw installations we walked through in this blog post: (hint - it's in step 6).

This quickstart relies on the riftsaw-2.0-SNAPSHOT/samples/quickstart/hello_world quickstart. Specifically, the bpel_helloworld quickstart invokes the RiftSaw BPEL process defined in the hello_world quickstart. So, before you run the bpel_helloworld quickstart, you have to deploy the hello_world quickstart.

The interesting part of the bpel_helloworld quickstart for us is this section of the jboss-esb.xml file:

<service
category="HelloWorldBPELESB"
name="SayHello"
description="Hello World">
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true" />
<jms-listener name="helloWorld"
busidref="quickstartEsbChannel" />
</listeners>
<actions>
<action name="action1" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="printfull" value="true"/>
</action>
<action name="action2" class="org.jboss.soa.esb.actions.bpel.BPELInvoke">
<property name="service" value="{http://www.jboss.org/bpel/examples/wsdl}HelloService"/>
<property name="operation" value="hello" />
<property name="requestPartName" value="TestPart" />
<property name="responsePartName" value="TestPart" />
</action>
<!-- The next action is for Continuous Integration testing -->
<action name="testStore" class="org.jboss.soa.esb.actions.TestMessageStore"/>
</actions>
</service>
  • Line 16: Here's where we start the definition of the BPELInvoke action.
  • Line 17: The service in the Riftsaw BPEL process to be invoked.
  • Line 18: And the operation.
  • Lines 19 and 20: The request and response WSDL parts.
This diagram illustrates the inter-relationship of the JBossESB bpel_helloworld quickstart and the RiftSaw BPEL process configuration files.



Before we run the quickstart, there's one more thing to look at; the client. In the case of the quickstart, this is the SendEsbMessage.java program. This program is invoked when you execute the "ant sendesb" ant target as defined on lines 11-20 in the quickstart build.xml file:

<project name="Quickstart_esb_bpel_hello_world" default="run" basedir=".">

<description>
${ant.project.name}
${line.separator}
</description>

<!-- Import the base Ant build script... -->
<import file="../conf/base-build.xml"/>

<target name="sendesb" depends="compile"
description="Will send an esb Message">
<echo>Runs Test ESB Message Sender</echo>
<java fork="yes" classname="org.jboss.soa.esb.samples.quickstart.helloworld.test.SendEsbMessage" failonerror="true">
<arg value="HelloWorldBPELESB"/> <!-- service category -->
<arg value="SayHello"/> <!-- service name -->
<arg value="Hello World via ESB to BPEL"/> <!-- Message text -->
<classpath refid="exec-classpath"/>
</java>
</target>

</project>

The command parameters are passed to SendEsbMessage.java. If we look at line 18 in that program (see below), we'll see that the client sends a message and receives a response. (Remember that with BPEL, all traffic follows a synchronous message exchange pattern.)

public class SendEsbMessage
{
public static void main(String args[]) throws Exception
{
// Setting the ConnectionFactory such that it will use scout
System.setProperty("javax.xml.registry.ConnectionFactoryClass","org.apache.ws.scout.registry.ConnectionFactoryImpl");

if (args.length < 3)
{
System.err.println("Usage SendEsbMessage <category><name> <text to send>");
System.exit(1);
}

Message esbMessage = MessageFactory.getInstance().getMessage();

esbMessage.getBody().add(args[2]);

Message respMessage = new ServiceInvoker(args[0],args[1]).deliverSync(esbMessage, 5000);

System.out.println("REPLY: "+respMessage.getBody().get());
}

}

OK, let's deploy and run the quickstart. Here are the ant commands and the output displayed by the client:

sendesb:
[echo] Runs Test ESB Message Sender
[java] REPLY: Hello World via ESB to BPEL World

BUILD SUCCESSFUL
Total time: 10 seconds
And here's the information written to the server log )I've truncated this a bit...)
22:57:05,591 INFO  [STDOUT] Message structure:
22:57:05,592 INFO [STDOUT] [ message: [ JBOSS_XML ]
.
.
.
context: {}
body: [ objects: {org.jboss.soa.esb.message.defaultEntry=Hello World via ESB to BPEL} ]
fault: [ ]
attachments: [ Named:{}, Unnamed:[] ]
properties: [ {org.jboss.soa.esb.message.byte.size=3920,
org.jboss.soa.esb.message.time.dod=Tue Nov 10 22:57:05 EST 2009,
javax.jms.message.redelivered=false} ] ]
OK, it's not exactly thrilling, but, if you look closely, you'll see that the client sent this message:
Hello World via ESB to BPEL
And the RiftSaw BPEL process replied with this:
Hello World via ESB to BPEL World
That's right. The hello operation in the RiftSaw BPEL process did its thing and appended "World" to the message!

Closing Thoughts

The fact that from the ESB's perspective, a RiftSaw BPEL process is a web service, makes orchestrating ESB processes a straightforward task. The corollary is also true, in that a JBossESB action can also invoke a RiftSaw BPEL process in the same manner as a web service. It's also possible, however, to invoke a RiftSaw BPEL process with one of the JBossESB's out-of-the-box actions, BPELInvoke. In the next post to this blog, we'll look how exceptions are handled across the RiftSaw-JBossESB integration.

Acknowledgments

As always, I want to thank the RiftSaw community (especially Kurt Stam and Gary Brown), both for creating RiftSaw, writing the user guide on which this blog entry is based, and for their timely review input for this blog post!

3 comments:

  1. thanks for the tutorial, but i'm not able to get it running, and i can't find the class BPELInvoke in any jars

    ReplyDelete
  2. I found the problem, Riftsaw 2.0M2 samples scripts need to be updated to work with jbossesb 4.7

    ReplyDelete
  3. Great that you found the problem. Version 2.0-CR1 is actually going to be released soon, which is tested to run on JBAS-5.1 and JBESB-4.7 (Riftsaw-2.0-M1 was released before JBESB-4.7). Anyway if you encounter any more issues, you probably find a larger audience of people that can help you on the user forum.

    Cheers,

    --Kurt

    ReplyDelete