Skip to main content

Web Services programming tips and tricks, Part 4: Bring J2EE and .NET together in a business process using BPEL and WebSphere Business Integration Server Foundation

Wangming Ye (yme@us.ibm.com), Software Engineer, WebSphere Competency Center, IBM, Software Group
Wangming Ye is an IBM Certified Enterprise Developer and a Sun Certified Enterprise Architect for J2EE Technology. He began as a developer in the DCE/DFS department at Transarc Corporation (later merged into IBM), and then as one of the main developers of the WebSphere Content Distribution Framework in the WebSphere Edge Server group. He currently provides technical enablement for WebSphere business partners in the WebSphere Competency Center in the IBM Business Partner Technical Enablement organization. You can reach Wangming at yme@us.ibm.com.

Summary:  Investigate a typical business integration scenario between J2EE (Java™ 2 Enterprise Environment) and Microsoft® .NET and learn how to build and run a BPEL (Business Process Execution Language) business process on IBM® WebSphere® Business Integration Server Foundation. In the first three parts of this series about improving interoperability between J2EE technology and .NET, Wangming Ye analyzed the common challenges facing a Web services integration between J2EE and .NET, and offered best practices. This tip focuses on the delicate design of XML schemas that Web services programmers often overlook. The objective is to show how to avert common Web service interoperability challenges between .NET and J2EE, such as nested complex-type arrays, date and time values, and namespace issues, through a top-down approach (WSDL (Web Services Description Language) implementations).

Date:  27 May 2005
Level:  Advanced
Activity:  2580 views

Note: You should be familiar with WebSphere Studio Application Developer Integration Edition Version 5.1.1 Web services development environment, ASP .NET Web services, and have knowledge of building a BPEL process. The sample code for the BPEL business process is included.

Introduction

BPEL, through its use of XML and Web services, has quickly become the cornerstone of Service-Oriented Architecture (SOA) implementations and provides the open standard for the WebSphere Application Server Enterprise Process Choreographer (Process Choreographer). Over the years, many business applications have been developed and deployed on J2EE platforms and .NET platforms, independently and in parallel. Those business applications are designed with fine-grained business functions. For example, in the J2EE world, information persistence is implemented using entity beans and business logic using session beans. Within the limited business domains, those business applications also provide an integration framework to integrate with back-end or legacy enterprise applications. For example, the Java Connector Architecture (JCA) and Java Messaging Service (JMS) are the typical integration frameworks for J2EE applications.

With the emergence of Web services, the back-end enterprise applications are exposed as discoverable and callable business services through the use of WSDL. WSDL defines the service semantics for the Web service interface, such as operations, protocol bindings, and message types. BPEL is a layer on top of WSDL; it specifies the behavior for the composite Web services participating in a process flow. Therefore, it enables business analysts and architects to define the logic of business process flow, and it makes it possible to use BPEL to support long-running conversations with J2EE Web Services and .NET Web Services.

In essence, whether a BPEL process flow succeeds or not all boils down to the XML service semantics defined in the WSDL document of each participant Web service. XML schemas differentiate XML from other file formats. XSD, the XML schema definition, is a comprehensive and complex data typing system. Simply put, XSD defines what an XML document should look like. Designing simple and strongly-typed objects from XSD is fundamental to Web services interoperability. "Improve interoperability between J2EE technology and .NET" (Part 1 of this series) pointed out that many Web services programmers neglect the importance of the XSD schema design.That is, they use their favorite programming language to code the Web services implementations and then derive the Web service semantics from the implementation using vendors' tools. This bottom-up approach creates interoperability problems.

A common source of interoperability problems between .NET and J2EE are issues resulting from the use of XML namespace and complex-data types, such as nested complex-type arrays and dates and times (Part 2 and Part 3 of the series). This tip shows how a nested array, complex types, and dates can be safely and accurately passed between the two platforms in the BPEL process integration, but only if you design the XSD schema for those complex types carefully.


Getting ready

To build the process, you must install IBM WebSphere Studio Application Developer V5.1.1 and Microsoft .NET Framwork 1.1 on a Windows machine. For this tip, both products are installed and run from the same machine. .NET Visual Studio is the integrated tool for building a .NET Web service, but for the purpose of this tip, it's not used.

By default, the document root for IIS is C:\Inetpub\wwwroot. I use this directory for publishing a .NET Web service. Also, the .NET Framework 1.1 is installed in C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322 and the SDK in c:\Program Files\Microsoft.NET\SDK\v1.1.

Add the following two directories to the system PATH variable:

  • c:\Windows\Microsoft.NET\Framework\v1.1.4322
  • c:\Program Files\Microsoft.NET\SDK\v1.1\Bin

The sample code for the BPEL business process is included in the Download section.


A typical interop business scenario

Consider a purchasing scenario in which a buyer works through a merchandise agent to fulfill an order request. The merchandise agent has a number of participating suppliers; each participant is an independent subscriber and has its own independent product inventory management system, which means one supplier might run J2EE Web services to manage its inventory and another to run .NET Web services.

The purchasing process begins with getting product quotes from different suppliers. Before a buyer submits an order, the agent communicates with each supplier for a product quote, and each supplier returns the detailed information about the product in its inventory. The buyer then reviews the information and proceeds with the next ordering process. Figure 1 shows a sequence diagram for the quote request with two participating suppliers: Supplier A and Supplier B. The buyer requests a quote from the agent, and the agent issues a quote request to each supplier and returns the composed quotes to the buyer.


Figure 1. Sequence diagram for the quote request
Sequence diagram for the quote request

In the diagram:

  • Buyer is the client who initiates the purchasing request.
  • Agent is the business process that requests product information from each supplier and places the order for the buyer.
  • Supplier A is the Java Web service managing the inventory for Supplier A.
  • Supplier B is the .NET Web service managing the inventory for Supplier B.

For the purchasing request from the buyer, the agent process first constructs a product quote request for each supplier. Each supplier responds with the product information, including the price, quantity, and other propriety product information. The agent then returns the composed product information for the buyer to review and enters the order.

The following sections build the Java Web service for Supplier A, .NET Web service for Supplier B, and the agent process.


Create the Java Web service for Supplier A

In Part 1 of this series, you found out that one of the foremost best practices often neglected is the design of the XML schemas and WSDL for a Web service. Programmers often start building Web services in their favorite programming language and then use vendor tools to derive the Web services semantics and expose the WSDL. This is a bottom-up approach -- it does not take into consideration the fact that Web services are message-centric and data and message types must be carefully designed, rather than generated by tools. This section shows how the XML schema and WSDL for a Web service can be designed using WebSphere Studio Application Developer Integration Edition Version 5.1.1.

For Supplier A, the inventory service must implement at least two operations: getQuote to return the product information in its inventory and fulfillOrder to fulfill the order request from the agent. Figure 2 below demonstrates this process for the service interface.


Figure 2. The interface diagram for Supplier A Web services
The Interface Diagram for Supplier A Web services

The Product is a flat complexType with four attributes; each is a primitive data type. This section shows how to leverage the XML schema editor in WebSphere Studio Application Developer Integration Edition Version 5.1.1 to define the product type in the XML schema language. The next section shows how to design a compound Product complexType for the .NET Web service to demonstrate the interoperability.

Step 1. Create a service project

First, create a service project and a package to hold the XML schema files and WSDLs for all of the partner Web services and process definitions.

  1. Start a new WebSphere Studio Application Developer Integration Edition Version 5.1.1 workspace.
  2. Select File>New>Service Project.
  3. Specify the service project name as QuoteProcessService and click Finish.
  4. Right-click on the QuoteProcessService project and select New>Package.
  5. Enter a new Java package name quote.process and click Finish.

Step 2. Create a new XML schema

Next, create a new XML schema and define the Product complexType.

  1. Right-click the package quote.process and select New>XML schema.
  2. Enter the new schema name SupplierASchema.xsd and click Finish. The XML schema editor opens.
  3. In the Outline view, select the SupplierASchema.xsd.
  4. In the Schema panel, enter http://schema.a.supplier as the namespace URI. This will be the target namespace for the schema. Click Apply.
  5. In the Outline view, right-click SupplierASchema.xsd and click Add Complex Type.
  6. In the Outline view, select NewComplexType.
  7. In the Complex Type panel, enter the name for the complex type: Product.
  8. In the Outline view, right-click the Product type and click Add Content Model.
  9. In the Outline view, expand the Product.
  10. Right-click the content model icon and click Add Element. A NewElement is added.
  11. In the Outline view, select the NewElement.
  12. In the Element panel, rename the NewElement as _name and set the type to xsd:string.

Notice that in Step 4, the target namespace for the schema is set to http://schema.a.supplier instead of http://a.supplier/schema. This is the result of the JAX-RPC behavior: JAX-RPC will make the domain name part of the URI to generate the package name for the serializable product class. To avoid potential naming conflicts, the domain name part of the namespace URI should be as fine-grained as possible, as illustrated in " Improve interoperability between J2EE technology and .NET, Part 3 ". Another reason for that is some clients will fail to find a de-serializer when the namespace qualified product object ({http://a.supplier/schema}Product) is received, while the Java package for the serializer class is supplier.a.

Repeat the last three steps, create the remaining elements for Product type and save the XSD file.

  • _price: xsd:float
  • _qty: xsd:int
  • _refurbished: xsd:boolean

Step 3. Create the WSDL for Supplier A

You can now design the WSDL for Supplier A and define the service methods (operations) and message bindings. In the quote process, getQuote is the only operation needed.

First, create a blank WSDL and import the product schema defined in the previous steps.

  1. Right-click the quote.process package. Select New>Other>Web Services>WSDL and click Next.
  2. Enter the new WSDL name SupplierAService.wsdl and click Next.
  3. In the wizard, set the target namespace to http://a.supplier/service/ and click Finish. The WSDL editor opens.
  4. In the Outline view, right-click Imports and select Add Child>Import.
  5. In the Import panel, click on the push button beside the location box.
  6. Browse to SupplierASchema.xsd and click OK.

The Product complexType is imported into the WSDL under the namespace http://schema.a.supplier.

Step 4. Create messages and message parts

Next, create the messages and message parts. For each getQuote invocation, there is a request message that sends the product name and a response message that returns the Product object from the inventory.

  1. In the Outline view, right-click Messages and select Add Child>Message.
  2. Enter the name getQuoteRequest.
  3. Right-click the newly created getQuoteRequest and select Add Child>Part.
  4. Name the new message part productName and click OK.

Notice that the message part name has a default type xsd:string. Accept the default. Now repeat the above steps. Create a new message getQuoteResponse with a message part product, which is the Product type defined in the imported SupplierASchema.xsd.

  1. Right-click the Product message part and click Set Type.
  2. Check Select Existing Type radio box, and select xsd1:Product, as shown in Figure 3 below. Click Finish.

Figure 3. Specify type for product message part
Specify type for product message part

Step 5. Define the Port Type

Next, define the Port Type, where all service operations are exposed. In this scenario, only the getQuote operation is defined.

  1. In the Outline view, right-click the Port Types and select Add Child>Port Type.
  2. Name the new port type SupplierAQuotePortType and click OK.
  3. Right-click SupplierAQuotePortType and select Add Child>Operation.
  4. Enter the new operation name getQuote and click OK.
  5. Right-click the getQuote operation and select Add Child>input.
  6. Right-click input>Set Message.
  7. Select the existing message tns:getQuoteRequest that you defined in Step 4. Create messages and message parts and click Finish.

Repeat the above three steps. Create an output for getQuote operation and link it to the tns:getQuoteResponse.

Step 6. Define the binding protocol

Finally, you can define the binding protocol for the service port.

  1. In the Outline view, right-click the Bindings and select Add Child>Binding.
  2. Specify the binding details, as shown in Figure 4 below. Make sure that document/literal is selected as the SOAP binding option. Click Finish.
  3. Right-click the Services and select Add Child>Service.
  4. Enter SupplierAQuoteService as the new service name and click OK.
  5. Right-click the SupplierAQuoteService and select Add Child>Port.
  6. Enter the port details as in Figure 5 and click Finish.

Figure 4. Specify binding details
Specify binding details

Figure 5. Specify service port details
Specify service port details

Step 7. Implement the Web service

Finally, you can implement a Web service based on the SupplierAService.wsdl and SupplierASchema.xsd. WebSphere Studio can generate a skeleton Java bean Web service from the WSDL.

  1. Select File>New>Other>Web Services>Web service and click Next.
  2. In the next Web Service Wizard, select Web service type Skeleton Java bean Web Service. Leave other fields as the default settings and click Next.
  3. In the next window, specify SupplierAServiceEAR as the Service project EAR and SupplierAServiceWeb as the Service Web project. This is the enterprise project that holds the Java Web service. Click Next.
  4. Browse to the SupplierAService.wsdl that you just created. Click OK, click Next, and click Finish.

Examine the SupplierAServiceWeb project. A serializable Product class is created from the complex type Product defined in SupplierASchema.xsd and a Java skeleton Web service is built. But this is an empty service that only has the interface functions; the concrete implementation of the interface operation getQuote needs to be provided by hand in the SupplierAQuoteServiceBindingImpl class.

First, add a constructor to the Product class.


Listing 1. Adding a constructor to the Product class
public Product(String name, int qty, float price, boolean isRefurbished) {
	this.set_name(name);
	this.set_qty(qty);
	this.set_price(price);
	this.set_refurbished(isRefurbished);
}

Next, add a constructor to the SupplierAQuoteServiceBindingImpl class to hard-code the inventory. In reality, you would need to expose an interface method, such as addInventory(Product item), to restock a product.


Listing 2. Adding a constructor to the SupplierAQuoteServiceBindingImpl class

private static Hashtable fCurrentInventory = new Hashtable();
public SupplierAQuoteServiceBindingImpl() {
	fCurrentInventory.put(
		"IBM ThinkPad T40",
		new Product("IBM ThinkPad T40", 200, 1499.99f, false));
	fCurrentInventory.put(
		"Dell Inspiron 4000",
		new Product("Dell Inspiron 4000", 100, 999.99f, true));
	fCurrentInventory.put(
		"Toshiba Satellite 2210X",
		new Product("Toshiba Satellite 2210X", 300, 599.99f, false));
}

Replace the getQuote method in the SupplierAQuoteServiceBindingImpl class with the code in Listing 3.


Listing 3. Replacing the getQuote method
public Product getQuote(java.lang.String productName)
	throws java.rmi.RemoteException {
	if (fCurrentInventory.containsKey(productName))
		return (Product) fCurrentInventory.get(productName);
	else
		return new Product(productName, 0, 0f, false);
}


The quote Web service for Supplier A is ready to deploy and run. You will not test until after BPEL process has been created.


Create the .NET Web service for Supplier B

For the .NET Web service for Supplier B, you will add a little more complexity to the schema: nesting an array of complex types inside another complex type. This added complexity isn't significant in a programming language and is quite a natural thing to do in reality, but it's the frequent source of the XML message serialization failure. Most notably, the message receiving side is often unable to match a proper XML serializer class.:dateTime is also a common source of interoperability problems between J2EE and .NET. One main purpose of this tip is to show how you can avoid the interoperability problem by carefully designing the XML schemas for the messages and data types.

To build the .NET Web service, you will use a slightly different approach. But the XSD schemas should always be designed first.

Assume Supplier B has a different requirement to keep its inventory product information. Instead of listing a product as refurbished or not as in Supplier A, Supplier B keeps a list of information for its products such as manufacturing date, inventory date, and restocking date.


Figure 6. The interface diagram for Supplier B Web service
The Interface Diagram for Supplier B Web service

In this UML diagram, Product has an attribute _dates, which is an aggregate of DateInfo, which in turn is a complex type. A UML aggregate translates to an array in a programming language. But on the other end, how is the relationship between the Product and the DateInfo represented in XML schema or as an XSD type? It needs another complex type ArrayOfDateInfo to represent the relationship. The ArrayOfDateInfo type will have an unbound sequence of elements of the DateInfo type. Therefore, to properly serialize the Product object in the .NET Web service, three complex types need to be defined in the XML Schema: DateInfo, ArrayOfDateInfo, and Product.

Similar to the steps illustrated in the previous section, first create a SupplierBSchema.xsd with the target namespace http://schema.b.supplier and define a complex type DateInfo, as shown in Listing 4.


Listing 4. Defining a complex type DateInfo
<complexType name="DateInfo">
   <sequence>
       <element name="_date" type="dateTime"/>
       <element name="_desc" type="string"/>
   </sequence>
 </complexType>

Next, add a complex type ArrayOfDateInfo with an unbounded sequence of elements of the DateInfo type in the SupplierBSchema.xsd.

  1. In the Outline view, right-click the SupplierBSchema.xsd and click Add Complex Type.
  2. Rename the new complex type ArrayOfDateInfo.
  3. Right-click on the ArrayOfDateInfo and click Add Content Model.
  4. Right-click on the content model icon and click Add element.
  5. Rename the new element as: DateInfo.
  6. Set the user-defined complex type: SupplierBSchema:DateInfo.
  7. Set minOccurs attribute to be zero and the maxOccurs attribute to be unbounded.

Listing 5 contains the resulting ArrayOfDateInfo schema.


Listing 5. The ArrayOfDateInfo schema
<complexType name="ArrayOfDateInfo">
   <sequence>
       <element maxOccurs="unbounded" minOccurs="0"
           name="_dateInfo" type="SupplierBSchema:DateInfo"/>
   </sequence>
</complexType>

Follow the similar steps to define the complexType Product, as shown in Listing 6 below.


Listing 6. The complexType Product
<complexType name="Product">
   <sequence>
       <element name="_name" type="string"/>
       <element name="_qty" type="int"/>
       <element name="_price" type="float"/>
       <element name="_dates" type="SupplierBSchema:ArrayOfDateInfo"/>
   </sequence>
</complexType>

In .NET Framework 1.1, the XML Schema Definition tool (Xsd.exe) can generate runtime classes from XSD files. The Xsd.exe utility generates a set of C# class templates from XSD schemas. From the templates, you can provide the concrete implementation and produce the whole project. However, the Xsd.exe utility requires at least one top-level element defined in the schema, so you'll define one global element: productItem.

  1. In the Outline view, right-click on the SupplierBSchema.xsd, and click Add Global Element.
  2. Name the element productItem and set the type to SupplierBSchema:Product.
  3. Save the file.

Now, export the SupplierBSchema.xsd file to a directory and run the Xsd.exe command in that directory to generate the C# type classes: xsd.exe SupplierBSchema.xsd /classes.

A set of C# type classes are generated in SupplierBSchema.cs file. The DateInfo and Product classes are defined and qualified by the http://schema.b.supplier namespace. See the complete source of classes in the Download section. Since you have just designed the most important piece in this interoperability scenario, you can start building the .NET Web service implementation. In Build the agent process section, the SupplierASchema.xsd and SupplierBSchema.xsd will also be the starting point to build the BPEL process.

To start building the Supplier B .NET Web service, you can either build the .NET assembly using .NET Visual Studio, or simply write C# code in an .asmx file and wrap the types classes in the SupplierBSchema.cs file. In this section, you'll use the latter approach.

  1. Copy the SupplierBSchema.cs file to the C:\Inetpub\wwwroot\SupplierB\ directory and rename it to SupplierBQuoteService.asmx, and open it in an editor.
  2. Comment out the following line: [System.Xml.Serialization.XmlRootAttribute("productItem", Namespace="http://schema.b.supplier", IsNullable=false)] .
  3. Add the constructors to the Product and DateInfo classes to do the initialization. In .NET, a default constructor is also needed for a serialization class:
    public DateInfo() {}
    public DateInfo(DateTime date, string desc) {
    	  _date = date;
    	  _desc = desc;
    }
    

    and
    public Product() {}
    public Product(string name, int qty, float price, DateInfo[] dates) {
    	_name = name;
    	_qty = qty;
    	_price = price;
    	_dates = dates;
    }
    

  4. Add a Web service class SupplierBQuoteService and expose a method getQuote under namespace http://b.supplier/service as a document/literal Web service method. In .NET, document/literal is the default binding style:
    [WebService(Namespace="http://b.supplier/service")]
    public class SupplierBQuoteService {
      private static Hashtable fCurrentInventory = null;
      private static Hashtable getCurrentInventory()
      {
    	  return fCurrentInventory;
      }
      public SupplierBQuoteService()
      {
    	  fCurrentInventory = new Hashtable();
    	  Product item1 = new Product("IBM ThinkPad T40", 200, 1399.99f, 
    		new DateInfo[] {new DateInfo(DateTime.Now, "Manufacture Date"), 
    		  new DateInfo(DateTime.Now.AddYears(3), "Expiry Date")});
    	  Product item2 = new Product("Dell Inspiron 4000", 200, 899.99f, 
    		new DateInfo[] {new DateInfo(DateTime.Now, "Manufacture Date"), 
    		  new DateInfo(DateTime.Now.AddYears(5), "Expiry Date")});
    	  Product item3 = new Product("Toshiba Satellite 2210X", 200, 599.99f, 
    		new DateInfo[] {new DateInfo(DateTime.Now, "Manufacture Date"), 
    		  new DateInfo(DateTime.Now.AddYears(10), "Expiry Date")});
    	  getCurrentInventory().Add("IBM ThinkPad T40", item1);
    	  getCurrentInventory().Add("Dell Inspiron 4000", item2);
    	  getCurrentInventory().Add("Toshiba Satellite 2210X", item3);
    }
    
      [WebMethod]
      public Product getQuote(string quoteItemName) {
    	  string item = quoteItemName;
    	  if (!getCurrentInventory().ContainsKey(item))
    		return new Product(item, 0, 0, 
    		  new DateInfo[] {new DateInfo(DateTime.Now, "Manufacture Date"), 
    			 new DateInfo(DateTime.Now, "Expiry Date")});
    	  else
    		return (Product)(getCurrentInventory()[item]);
      }
    }
    

The complete SupplierBQuoteService.asmx file is included in the Download section.

Now you can test the getQuote method of the Supplier B Web service from the browser.

  1. From a browser, enter the following URL: http://localhost/SupplierB/getQuoteServiceImpl.asmx.
  2. The only Web service method getQuote is returned. Click on the getQuote method.
  3. Enter IBM ThinkPad T40 in the item text box and click Invoke.

The product information for an IBM ThinkPad T40 is returned, as shown in Figure 7 below.


Figure 7. Test result for the getQuote method of the .NET Web service
Test result for the getQuote method of the .NET Web service

Notice how the Manufacture Date and the Expiry Date are displayed.

Enter the URL: http://localhost/SupplierB/SupplierBQuoteService.asmx?wsdl in the browser. The browser displays the WSDL document for the .NET Web service. Even though it's generated by the .NET WSDL engine, the data type schemas and namespace come directly from the SupplierBSchema.xsd that was designed in earlier steps. Import this WSDL into the quote.process package in the service project.


Build the agent process

In this section, you'll define the agent Quote Process interface. The output data type of the process is the combined result of product quotes from Supplier A and Supplier B, as shown in the UML diagram in Figure 8.


Figure 8. The interface diagram for the Quote Process
The Interface Diagram for the Quote Process

You need to define a complex type to compose the final quotes by importing the two Product complex types from SupplierASchema.xsd and SupplierBSchema.xsd.

Step 1. Define a complex type

First, create a QuoteProcess.xsd schema file and import both SupplierASchema.xsd and SupplierBSchema.xsd:

  1. Right-click on the quote.process package and select New>XML Schema.
  2. Enter the new schema name: QuoteProcessSchema.xsd and click Finish. The schema editor opens.
  3. In the Outline view, select the QuoteProcessSchema.xsd.
  4. In the Outline view, right-click on the QuoteProcessSchema.xsd and click Add Import.
  5. In the Outline view, expand the + sign and click the import icon.
  6. In the Import panel, browse to the SupplierASchema.xsd file and click Finish.

Repeat the Steps 4 to 6 and import the SupplierBSchema.xsd file.

Step 2. Create the complex type

Next, create the complex type ProductQuotes:

  1. In the Outline view, right-click on the QuoteProcess.xsd and click Add Complex Type.
  2. In the Complex Type window, name the new complex type ProductQuotes.
  3. In the Outline view, right-click the ProductQuotes and click Add Content Model.
  4. In the Outline view, right-click on the icon: and click Add Element.
  5. In the Element window, name the new element SupplierAQuote.
  6. Set the SupplierAQuote element to the user-defined complex type SupplierASchema:Product.

Repeat the last three steps to add another element SupplierBQuote with the user-defined complex type SupplierBSchema:Product.

In the Source view, the resulting ProductQuotes schema is shown in Listing 7.


Listing 7. The ProductQuotes schema
<?xml version="1.0"?>
<schema targetNamespace="http://www.ibm.com"
    xmlns="http://www.w3.org/2001/XMLSchema"
    xmlns:QuoteProcessSchema="http://www.ibm.com" 
    xmlns:SupplierASchema="http://schema.a.supplier"  xmlns:SupplierBSchema=
      "http://schema.b.supplier">
    <import namespace="http://schema.b.supplier" schemaLocation=
      "SupplierBSchema.xsd"/><import schemaLocation=
        "SupplierASchema.xsd" namespace="http://schema.a.supplier"/>
	<complexType name="ProductQuotes">
        <sequence>
            <element name="SupplierBQuote" type="SupplierBSchema:Product"/>
            <element name="SupplierAQuote" type="SupplierASchema:Product"/>
        </sequence>
    </complexType>
</schema>


The BPEL process will be deployed and run as a Web service, so the next step is to create the process interface WSDL and import the QuoteProcessSchema.xsd.

Step 3. Create the process interface WSDL

Create the process interface WSDL.

  1. Create a blank WSDL in the package quote.process and name it quoteProcessClient.wsdl. In the Wizard, set the target namespace to http://quote.process/quoteProcessClient/.
  2. When the WSDL editor opens in the Outline view, right-click on the Imports and import the QuoteProcessSchema.xsd file.

Step 4. Define the process inbound and outbound messages

Next, define the process inbound and outbound messages.

  1. In the Outline view, right-click on the Messages and select Add Child>Message.
  2. Set the new message name to getQuotesRequest and click OK.
  3. In the Outline view, right-click on the getQuotesRequestand select Add Child>Part.
  4. Enter the part name productName. The default xsd:string is its type.

Repeat the above steps, create a new message getQuotesResponse, add a message part quotes, and set the type for quotes.

  1. In the Outline view, right-click on quotes and click Set Type.
  2. Specify the type to be xsd1:ProductQuotes and click Finish, as shown in Figure 9 below.

Figure 9. Specify type for the quotes
Specify Type for the quotes

Step 5. Add port types

Next, add Port Types and operation for the process and define the input and output.

  1. In the Outline view, right-click on Port Types and select Add Child>Port Type.
  2. Add the new Port Type name QuotesProcessPortType.
  3. Right-click on QuotesProcessPortType and select Add Child>Operation.
  4. Name the operation getQuotes.
  5. Right-click on the operation getQuotes, select Add Child>input, and right-click on input.
  6. Click Set Message and select the Select an existing message radio box.
  7. Set the message for the input to be tns:getQuotesRequest and click Finish.

Repeat the last three steps, add an output, set the message to be tns:getQuotesResponse, and save the quoteProcessClient.wsdl.

Step 6. Construct the business process flow

Now construct the business process flow. First, create an empty process definition file.

  1. Right-click on the quote.process package in the QuoteProcessService and select New>Business Process.
  2. Set business process name to be QuotesProcess and click Next.
  3. Select Sequence-based BPEL Process and click Finish.

Step 7. Create the partner link

A BPEL process invokes a Web service through a simple concept called <partnerLink>. A <partnerLink> is a BPEL abstraction of the operations defined in a Web service WSDL file. A partner link reads the portType of the external Web service defined in the WSDL and allows an invoke activity to be associated with an actual operation in the portType. Each partner link is associated with a logical role.

In this process, there are three partners: Agent, Supplier A, and Supplier B. The interface for each partner service is described in its WSDL file: quoteProcessClient.wsdl, SupplierAService.wsdl, and SupplierBService.wsdl, respectively.

  1. Double-click on the quotesProcess.bpel file to open it in the editor and delete the default partner link.
  2. Drag and drop the quoteProcessClient.wsdl into the editor and accept the default.
  3. In the editor, select the QuotesProcessPortType partner link. In the details area, click the Implementation tab and click the role switch icon to promote the QuotesProcessPortTypeRole as the process role name.
  4. Similarly, drag and drop the SupplierAService.wsdl and SupplierBService.wsdl files into the editor; accept the defaults.

Step 8. Define the process variables

Next, define the process variables. The process state information flow is managed by process variables. In WebSphere Studio Application Developer Integrated Edition V5.1.1, all of the process variables created are global. So, you can access the process variables from any code block. Each partner link has input and output variables, thus three pairs of variables need to be defined in the quotesProcess.

  1. In the BPEL editor, delete the default InputVariable.
  2. Click the plus icon and add a new variable named Input.
  3. In the details area, click the Message tab and browse to the quoteProcessClient.wsdl file and link it to the getQuotesRequest message.

Repeat the same steps and create the following process variables. Link them to their respective messages, as shown in the following table:

VariableMessageWSDL
OutputgetQuotesResponsequoteProcessClient.wsdl
SupplierAQuoteReqgetQuoteRequestSupplierAService.wsdl
SupplierAQuoteResgetQuoteResponseSupplierAService.wsdl
SupplierBQuoteReqgetQuoteSoapInSupplierBService.wsdl
SupplierBQuoteResgetQuoteSoapOutSupplierBService.wsdl

Step 9. Implement the Receive and Reply activities

Next, implement the Receive and Reply activities. The Receive activity receives the Web service request, which initiates the quote process. The Reply activity sends the quotes response to the caller using a Web service call.

  1. Click the Receive activity.
  2. In the Details area, click the Implementation detail tab and set the PartnerLink to QuotesProcessPortType. Set the Operation to getQuotes and the Request to Input.
  3. Similarly, for the Reply activity, set the PartnerLink to QuotesProcessPortType. Set the Operation to getQuotes and the Response to Output.

Step 10. Create Flow and Sequence activities

A Flow activity is a group of activities that run in parallel, and a Sequence activity is a group of activities that run in sequence. In the agent quotes process, you want to invoke the Web services for Supplier A and Supplier B in parallel. So, create a Flow activity in which two sequence activities run in parallel, and each Sequence activity prepares the call, invokes the Web service of the supplier, and processesnot the result. In BPEL, the Invoke activity is used to execute the business logic implemented externally in a Web service.

  1. From the Palette, select a Flow activity and drop it into the editor between the Receive and Reply activities.
  2. From the Palette, select a Sequence activity and drop it into the Flow activity. Name the Sequence activity QuoteSupplierA.
  3. Prepare the variables for invoking the Supplier A Web service. On the Palette, select an Assign activity and drop it inside the QuoteSupplierA sequence activity. Name it Init.
  4. In the Implementation details area, copy the input part of the getQuotesRequest message of the Input variable to the productName part of the getQuoteRequest of the SupplierAQuoteReq variable.
  5. Drop an Invoke activity in the QuoteSupplierA sequence activity and below the Init activity. Rename it to getQuote.
  6. In the Implementation details area, set the getQuote activity to the Partner Link SupplierAQuotePortType, the Operation to getQuote, the Request message to SupplierAQuoteReq and the Response message to SupplierAQuoteRes.

Step 11. Create an Invoke activity

Next, create an Invoke activity for Supplier B. Here you'll use a Java snippet for the initialization of process variable getSupplierBQuoteReq for the invocation of Supplier B Web service. You can also use a Java snippet to implement simple business logic that does not involve the external Web services.

  1. Drop a Sequence activity on the canvas inside the Flow activity and name it QuoteSupplierB. QuoteSupplierB is a parallel sequence activity to the QuoteSupplierA.
  2. Drop a Java snippet inside the QuoteSupplierB sequence activity and rename it Init.
  3. In the Implementation detail area for the Init Java snippet, copy and paste the following code:
    supplier.b.service.GetQuoteElement newValue = 
      new supplier.b.service.GetQuoteElement();
    newValue.setQuoteItemName(getInput(true).getInput());
    getSupplierBQuoteReq(true).setParameters(newValue);
    

  4. Drop an Invoke activity below the Init in QuoteSupplierB. Rename it to getQuote.
  5. Set the getQuote activity to Partner Link SupplierBQuoteServiceSoap, Operation to getQuote, Request message to SupplierBQuoteReq, and Response message to SupplierBQuoteRes.
  6. Now drop a Java snippet immediately after the Flow activity, but before the Reply activity to prepare the output. Name it preReply.
  7. Copy and paste the following code snippet in the Implementation detail area for the preReply Java snippet:
    ProductQuotes newValue = new ProductQuotes();
    newValue.setSupplierBQuote(getSupplierBQuoteRes(true).
      getParameters().getGetQuoteResult());
    newValue.setSupplierAQuote(getSupplierAQuoteRes(true).getProduct());
    getOutput(true).setOutput(newValue);
    

Now, you have the complete quote process defined as in Figure 10.


Figure 10. The agent Quotes process
The agent Quotes process

Step 12. Generate the deploy code

Save the BPEL file and generate the deploy code.

  1. Right-click the quotesProcess.bpel file and select Enterprise Services>Generate deploy code.
  2. In the Generate BPEL Deploy Code wizard, click the quotesProcessPortType interface.
  3. Select SOAP/HTTP as the binding and select the IBM Web Service. Click OK.

The agent process is deployed as a SOAP/HTTP Web service. The WSDL and XSD files in the QuotesProcessServiceWeb project expose its interface for any clients to invoke the process.


Figure 11. WSDL and XSDs for the agent process
WSDL and XSDs for the agent process

Generate a Java client proxy to interface with the agent process

In this section, you can use the process WSDL and XSD files in Figure 11 to generate a Java client proxy invoked by the buyer in your business scenario, as shown in Figure 1.

First, create a Java project QuoteProcessTestClient and copy the WSDL and the three XSD files from the QuoteProcessServiceWeb to the test client project.

Next, generate a JAX-RPC client proxy from the WSDL.

  1. Right-click QuotesProcess_QuotesProcessPortType_HTTP.wsdl file and select Enterprise Services>Generate Service Proxy.
  2. In the wizard, select Java API for XML-based RPC (JAX-RPC) as the proxy type, click Next, and click Next again.
  3. Make sure that Java is selected as the Client type and QuoteProcessTestClient is selected as the Client project. Click Next.
  4. Accept all the default options in the following pages and click Finish.

The set of classes for JAX-RPC proxy are generated, as shown in Figure 12, except for the Buyer.java in the testclient package, which will be created in the next section.


Figure 12. JAX-RPC proxy for the agent process
JAX-RPC proxy for the agent process

Test the agent process

To test the agent process, first create a test server and deploy the Supplier A Web service and the agent process on the server.

  1. Switch to the Server perspective. Create a new integration test server and configuration and name it TestServer.
  2. In the Servers window, right-click the TestServer. Click Add and Remove Projects.
  3. Add the two projects: SupplierAServiceEAR and QuoteProcessServiceEAR on the TestServer. Click Finish.
  4. Right-click the TestServer and click Start.

Next, implement a main class representing the Buyer to call the JAX-RPC proxy to invoke the agent process.

  1. Create a new Java package. Right-click the QuoteProcessTestClient, select New>Package, and name the new Java package as testclient. Click Finish.
  2. Create a Buyer class. Right-click the testclient package, select New>Class, and name the new class as Buyer. Click Finish. The Buyer class opens.
  3. Copy and paste the code in Listing 8 onto the Buyer class editor and save the Java file.

Listing 8. The Buyer class

package testclient;

import java.util.Calendar;
import java.util.Date;
import process.quote.QuotesProcessPortTypeProxy;
import supplier.b.schema.DateInfo;
import com.ibm.www.ProductQuotes;

public class Buyer {
  public static void main(String[] args) {
	String product = "IBM ThinkPad T40";
	QuotesProcessPortTypeProxy aProxy = new QuotesProcessPortTypeProxy();
	try {
	  ProductQuotes result = aProxy.getQuotes(product);
	  supplier.a.schema.Product quoteA = result.getSupplierAQuote();
	  supplier.b.schema.Product quoteB = result.getSupplierBQuote();

	  System.out.println("Quotes for product: " + product);
	  System.out.println("\tSupplier A: ");
	  System.out.println("\t\tQuantity: " + quoteA.get_qty());
	  System.out.println("\t\tPrice: " + quoteA.get_price());
	  System.out.println(
		  "\t\tIs refurbished: " + quoteA.is_refurbished());

	  System.out.println("\tSupplier B: ");
	  System.out.println("\t\tQuantity: " + quoteB.get_qty());
	  System.out.println("\t\tPrice: " + quoteB.get_price());

	  DateInfo[] dates = quoteB.get_dates().get_dateInfo();
	  for (int i = 0; i < dates.length; i++) {
		  Calendar cal = dates[i].get_date();
		  Date date = cal.getTime();

		  System.out.println("\t\t" + dates[i].get_desc() + ": " + date);
	  }
	} catch (Exception e) {
	  e.printStackTrace();
	}
  }
}

Finally, the Buyer class can be run to get the product information from Supplier A and Supplier B for product IBM ThinkPad T40.

  1. Select the Buyer class in the Package Explorer.
  2. From the top menu, select Run>Run As>Java Application. Upon successful completion, the result appears in the console, as shown in Figure 13 below.

Figure 13. The quote result
The quote result

Compare Figure 13 with the unit test result in Figure 7, and observe how the array of the date information is represented in each case.

The xsd:dateTime is mapped to the java.util.Calendar in agent process and its client proxy class, but it's a lot more desirable to present the buyer with the concise java.util.Dates result instead of the java.util.Calendar, which includes lots of extra information. A simple conversion is needed if the client is expecting a java.util.Dates, as shown in Listing 8.


Miscellaneous

Here are some miscellaneous tips for developing the BPEL process for J2EE and .NET:

  • The WebSphere Studio Application Developer Integration Edition Version 5.1.1 provides a powerful visual process debugger to step through the code at the BPEL process level.
  • You need to intercept and investigate the SOAP messages going to and from the participating Web services, particularly the .NET Web services. There are numerous trace tools that you can use for that. WebSphere provides a utility class com.ibm.ws.webservice.engine.utils.tcpmon to sniff the HTTP traffic between two points. Choose a tool that you are familiar with.
  • In many cases, it migh be necessary to turn on the server tracing to look for the root of exceptions.

Summary

What determines the success or failure of business process integration through BPEL is the inherent interoperability of the participating Web services. This tip emphasizes that message schemas should be designed carefully, and it demonstrates that both simple and complex Web services can be brought into a business process successfully, regardless of the platforms (J2EE versus .NET). The tip also shows that the WebSphere Studio Application Developer Integrated Edition V5.1.1 provides a powerful BPEL process development environment, convenient XML Schema, and WSDL design tools.



Download

DescriptionNameSizeDownload method
Code for sample BPEL business process (Purchasing)ws-solution.zip153 KB HTTP

Information about download methods


Resources

About the author

Wangming Ye is an IBM Certified Enterprise Developer and a Sun Certified Enterprise Architect for J2EE Technology. He began as a developer in the DCE/DFS department at Transarc Corporation (later merged into IBM), and then as one of the main developers of the WebSphere Content Distribution Framework in the WebSphere Edge Server group. He currently provides technical enablement for WebSphere business partners in the WebSphere Competency Center in the IBM Business Partner Technical Enablement organization. You can reach Wangming at yme@us.ibm.com.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=84122
ArticleTitle=Web Services programming tips and tricks, Part 4: Bring J2EE and .NET together in a business process using BPEL and WebSphere Business Integration Server Foundation
publish-date=05272005
author1-email=yme@us.ibm.com
author1-email-cc=flanders@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers