Chapter 5. Hello World Example

In this example, we will develop a trivial BPEL process that receives a person name, composes a greeting phrase and finally replies with the greeting. The resources related to this example come with in the download package. Look in examples/hello.

The following picture represents the Hello World process.

Hello world process

Figure 5.1. Hello world process

5.1. Define the BPEL process

5.1.1. Create the BPEL document

The first step is creating the process definition document. The description ahead assumes familiarity with the BPEL concepts. Even if you are new to BPEL, we hope you will find it easy to follow. If you get interested in BPEL and decide to take it to a real project, you should read the specification in its entirety. The OASIS BPEL Technical Committee web site provides the specification document and handful related resources.

Let us call our process document hello.bpel. We create a partner link to establish a relationship with the client of the process. We indicate that the process will play the Greeter role. Next we create two variables to hold the incoming and outgoing messages. Finally, we create a sequence of three activities that receives a request message from a client, prepares a response message and sends it back.

<process name="HelloWorld" targetNamespace="http://jbpm.org/examples/hello"
  xmlns:tns="http://jbpm.org/examples/hello"
  xmlns:bpel="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
  xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/">

  <partnerLinks>
    <!-- establishes the relationship with the caller agent -->
    <partnerLink name="caller" partnerLinkType="tns:Greeter-Caller" myRole="Greeter" />
  </partnerLinks>

  <variables>
    <!-- holds the incoming message -->
    <variable name="request" messageType="tns:nameMessage" />
    <!-- holds the outgoing message -->
    <variable name="response" messageType="tns:greetingMessage" />
  </variables>

  <sequence name="MainSeq">

    <!-- receive the name of a person -->
    <receive name="ReceiveName" operation="sayHello" partnerLink="caller" 
      portType="tns:Greeter" variable="request" createInstance="yes" />

    <!-- compose a greeting phrase -->
    <assign name="ComposeGreeting">
      <copy>
        <from expression="concat('Hello, ', bpel:getVariableData('request', 'name'), '!')" />
        <to variable="response" part="greeting" />
      </copy>
    </assign>

    <!-- send greeting back to caller -->
    <reply name="SendGreeting" operation="sayHello" partnerLink="caller" 
      portType="tns:Greeter" variable="response" />

  </sequence>

</process>

Note

The partnerLinkType and messageType attributes refer to external WSDL definitions. We will deal with them in the next section.

5.1.2. Create/obtain the WSDL interface documents

WSDL documents describe the interface of the process that will be presented to the outside world. To promote clarity and reuse, the WSDL specification recommends separating the different elements of a service definition into independent documents according to their level of abstraction. The proposed levels are data type definitions, abstract definitions, and specific service bindings.

A service interface document describes a specific type of service. It contains the types, import, message and portType elements; it can reference other abstract definitions documents using import elements. A service implementation document contains the description of a service that implements a service interface. It contains the import, binding and service elements. One of the import elements references the WSDL interface document.

The process definition is dependent on data type definitions and abstract definitions. The BPEL runtime is responsible of supplying the specific bindings for web services produced by a BPEL process. The specific bindings for partner services can be typically obtained at deployment or runtime.

We use only one WSDL interface document. Let's name it hello.wsdl. We create two messages that respectively carry the name and greeting. Next we create a port type that describes the interface that the process presents to its callers. It exposes a single operation sayHello, which takes the name message as input and returns the greeting message as output.

Once the service interface is defined, we create a partner link type to characterize the relationship between greeter and caller. We define the roles played by each service and specify the interfaces (i.e. port types) they expose to each other. Because our greeter process does not call the client back, only one role appears. No responsibilities are placed on the caller.

<definitions targetNamespace="http://jbpm.org/examples/hello"
  xmlns:tns="http://jbpm.org/examples/hello"
  xmlns:plt="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns="http://schemas.xmlsoap.org/wsdl/">

  <!-- carries the name of a person -->
  <message name="nameMessage">
    <part name="name" type="xsd:string" />
  </message>

  <!-- carries the greeting -->
  <message name="greetingMessage">
    <part name="greeting" type="xsd:string" />
  </message>

  <!-- describes the interface presented to callers -->
  <portType name="Greeter">
    <operation name="sayHello">
      <input message="tns:nameMessage" />
      <output message="tns:greetingMessage" />
    </operation>
  </portType>

  <!-- characterizes the relationship between the greeter and its caller -->
  <plt:partnerLinkType name="Greeter-Caller">
    <plt:role name="Greeter">
      <plt:portType name="tns:Greeter" />
    </plt:role>
    <!-- the Caller does not provide services to the Greeter,
      this is why we omit the "Caller" role -->
  </plt:partnerLinkType>

</definitions>

Observe that name attributes in the above description match the names used earlier in the process definition.

5.1.3. Deploy the process definition

jBPM provides a mechanism to extract the resources that make up a process definition from a ZIP file, dubbed a process archive. jBPM BPEL uses the following ordered procedure to identify the documents within the process archive:

  1. Read a definition descriptor, if present
  2. Rely on automatic discovery

The definition descriptor specifies the location of the process document within the process archive. In addition, the descriptor indicates the location of the WSDL descriptions and XML Schemas, as either (1) a path relative to the archive root, or (2) an absolute URL. The descriptor must be placed in this exact location: META-INF/bpel-definition.xml.

The automatic discovery strategy looks for a file inside the process archive whose name ends with .bpel. This file is treated as the process document. For BPEL 2, the process document itself indicates the location of the interface WSDL documents. For BPEL 1.1, the archive is expected to contain a WSDL file co-located with the process document, having the .bpel suffix replaced with .wsdl. Such WSDL file acts as the source of all WSDL definitions and XML Schema types, by containment or reference.

All examples shipped with the jBPM BPEL distribution rely on automatic discovery. For your reference, a sample definition descriptor appears below.

<bpelDefinition location="hello.bpel" 
  xmlns="urn:jbpm.org:bpel-1.1:definition">

  <imports>
    <wsdl location="hello.wsdl" />
  </imports>

</bpelDefinition>

To deploy the process definition to the jBPM database, call:

ant deploy.process

This will build a file named hello.zip and submit it to the jBPM BPEL deployment servlet. When successful, the messages below appear in the server console:

13:16:43,718 INFO  [DeploymentServlet] deployed process definition: HelloWorld
13:16:49,718 INFO  [WebModuleBuilder] packaged web module: hello.war
13:16:49,718 INFO  [DeploymentServlet] deployed web module: hello.war
13:16:50,109 INFO  [DefaultEndpointRegistry] register: jboss.ws:context=hello, «
endpoint=GreeterServlet
13:16:50,125 INFO  [TomcatDeployer] deploy, ctxPath=/hello, warUrl=...
13:16:50,484 INFO  [IntegrationConfigurator] message reception enabled for process: «
HelloWorld
13:16:50,546 INFO  [WSDLFilePublisher] WSDL published to: .../hello-service.wsdl

There is a page in the jBPM BPEL web console that displays the currently deployed process definitions. You can deploy new processes as well.

Process definitions page

Figure 5.2. Process definitions page

At this point, your BPEL process is fully available to external clients through its service endpoint. In JBoss 4.0.4.GA and later, the JBossWS services page lists the available service endpoints. The endpoint exposed by this process is shown below.

Service endpoints page

Figure 5.3. Service endpoints page

5.2. Build the WSEE application client

Since a Java mapping generator available, the WSEE client programming model is a most comfortable choice for test purposes. In this step, we will create an application client to contact the BPEL process we just deployed.

The WSEE client programming model is not covered in detail here. If you want to know more about it, the JBossWS user guide provides a good description on the subject.

5.2.1. Application client deployment descriptor

J2EE application clients read deployment settings from application-client.xml, reproduced below for your convenience. The directory for client descriptors is src/main/resources/client.

<application-client version="1.4" xmlns="http://java.sun.com/xml/ns/j2ee">

  <display-name>Hello World Service Client</display-name>

  <service-ref>

    <!-- JNDI name for Service instance, chosen by the user -->
    <service-ref-name>service/Hello</service-ref-name>
    <!-- fully qualified name of Service interface, generated by the mapping tool -->
    <service-interface>org.jbpm.bpel.tutorial.hello.HelloWorldService</service-interface>
    <!-- published WSDL document, taken from server -->
    <wsdl-file>META-INF/wsdl/hello-service.wsdl</wsdl-file>
    <!-- Java mapping document, generated by the mapping tool -->
    <jaxrpc-mapping-file>META-INF/hello-mapping.xml</jaxrpc-mapping-file>

  </service-ref>

</application-client>

Application clients must have access to the full WSDL description as well as the Java mapping artifacts. We say a WSDL description is full when it provides not only abstract definitions but also service bindings. The WSDL file we saw in Create/obtain the WSDL interface documents contains abstract definitions only.

On the server, the WsdlServiceTool has already generated service bindings for the given abstract definitions. In turn, the WSDLFilePublisher published the full WSDL description to a known location; namely, the data/wsdl directory of the server configuration.

Both Java mapping generators supported by jBPM BPEL read a configuration file, which references the above WSDL description, among other settings. The directory for configuration files is src/main/resources. The next listing presents the configuration for wstools.

<configuration xmlns="http://www.jboss.org/jbossws-tools">
  <global>
    <package-namespace package="org.jbpm.bpel.tutorial.hello"
      namespace="http://jbpm.org/examples/hello" />
  </global>
  <wsdl-java file="wsdl/hello-service.wsdl">
    <mapping file="hello-mapping.xml" />
  </wsdl-java>
</configuration>

For wscompile, we have:

<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
  <wsdl location="target/resources/web/wsdl/hello-service.wsdl"
    packageName="org.jbpm.bpel.tutorial.hello" />
</configuration>

5.2.2. Environment context

In order to provide an environment context for the application client, we must allocate an entry in the server JNDI registry. The desired entry is specified in the jboss-client.xml descriptor. Notice this descriptor is specific to JBoss AS.

<jboss-client>
  <!-- JNDI name for client environment context, chosen by the user -->
  <jndi-name>jbpmbpel-client</jndi-name>
</jboss-client>

5.3. Test the process

Once the process starts, we need to make sure it works as we expect. In this step, we will create a JUnit test case named HelloTest.

5.3.1. Remote web service access

Deploying the application client from Build the WSEE application client causes the app server to bind an instance of the service interface in the client environment context, using the logical name from the service-ref element. In this example, the logical name is service/Hello.

The test setup code looks up the service instance. This object is a factory that clients employ to get a service endpoint proxy.

private HelloWorldService service;

protected void setUp() throws Exception {
  InitialContext iniCtx = new InitialContext();
  /*
   * "service/Hello" is the JNDI name of the service interface instance
   * relative to the client environment context. This name matches the
   * <service-ref-name> in application-client.xml
   */
  service = (HelloWorldService) iniCtx.lookup("java:comp/env/service/Hello");
}

The test method uses the SEI proxy like a local java object.

public void testSayHello_proxy() throws Exception {
  // obtain dynamic proxy for web service port
  Greeter proxy = service.getGreeterPort();
  // use proxy as local java object
  String greeting = proxy.sayHello("Popeye");
  // check proper greeting
  assertEquals("Hello, Popeye!", greeting);
}

5.3.2. Client JNDI properties

The properties of the initial JNDI context are supplied in a separate jndi.properties file. The property j2ee.clientName indicates the JNDI name of the client environment context relative to the global context. The value jbpmbpel-client matches the <jndi-name> in jboss-client.xml.

java.naming.provider.url=jnp://localhost:1099
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming.client
j2ee.clientName=jbpmbpel-client

5.3.3. Test execution

To execute the JUnit test, call:

ant test

If all goes well you should see the output below:

test:
    [junit] Running org.jbpm.bpel.tutorial.hello.HelloTest
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 3.625 sec

For a detailed test report, including a printout of the SOAP messages exchanged with the server, look in the target/test/reports directory. You should see messages that look like the entries below.

06:11:49,343 TRACE [MessageTrace] Outgoing Request Message
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
 <env:Header/>
 <env:Body>
  <ns1:sayHello xmlns:ns1='http://jbpm.org/examples/hello'>
   <name>Popeye</name>
  </ns1:sayHello>
 </env:Body>
</env:Envelope>
06:11:49,546 TRACE [MessageTrace] Incoming Response Message
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
 <env:Header/>
 <env:Body>
  <operationNS:sayHelloResponse xmlns:operationNS='http://jbpm.org/examples/hello'>
   <greeting>Hello, Popeye!</greeting>
  </operationNS:sayHelloResponse>
 </env:Body>
</env:Envelope>