So far in this series of articles, we explored the basics of WebSphere V6 Messaging Resources, how to set up an Enterprise Service Bus (ESB), how to use JMS as a message protocol going across the bus, and how to develop and install a simple mediation. Our overall solution has evolved from these previous articles:
- Part 1: Introduction to WebSphere V6 messaging resources
- Part 2: Business requirements and the bus
- Part 3: A simple JMS messaging example
- Part 4: Building a better bus with mediations
Here, in Part 5, we will configure the bus to route SOAP requests from clients to a SOAP provider.
SIBus Web services support
As we explained in Part 1, WebSphere V6 Messaging Resources has support for receiving a SOAP request from a SOAP client, and can send a SOAP request to a SOAP provider using destinations, mediations, and additional SOAP bus artifacts. The system integration bus (SIBus) enables Web services messages -- including dynamic routing and transformation -- as just another message type. The goal of using an ESB for Web services is to decouple the requestor and the provider of a service so that additional qualities of service and management can be applied in the bus. Importantly, none of this has any impact on the programming model for Web services; any SOAP requestor or provider can be used with the bus.
The SIBus Web services support consists of inbound services which process SOAP messages that are sent into the bus, and outbound services that send SOAP messages to a Web service provider. The SIBus support in the WebSphere Application Server administrative console has wizards to consume a Web Services Description Language (WSDL) file for a service and to generate the artifacts for an inbound or outbound service. As is typical in Web services, WSDL is the key to the definition and processing of messages.
Our business scenario
At Posts-R-Us, there are many systems with a need to know the status of a package based on its tracking number. (See Part 3 for some background on our business example.) Due to acquisitions and silos at the company, backend systems for package tracking encompasses many different types of packages, as well as different geographies with their own tracking systems. There are dozens of possible unique implementations to obtain package status. As part of the company's move to a Service Oriented Architecture (SOA), they wish to create an enterprise service for package tracking to be used by all new applications, and to be migrated for use by older applications over time. They also plan to provide some of this tracking functionality to business partners using SOAP/HTTP.
They want to make the service available on the bus for several reasons:
- To support invocation from multiple protocols.
- To hide the real address of the service from partner applications.
- To achieve location transparency to be able to move the service.
- To have dynamic routing to support changes in backend service configurations.
- To have centralized logging and security.
The first step for Posts-R-Us is to create a scaled-down enterprise service, PackageTrackingService, which only accesses a couple of backend systems (for the purpose of this article, we will use a simple JavaBean service which returns dummy values and will only implement one operation of the service), and use the service for one new application being written.
The key to making the PackageTrackingService an enterprise service is to define the WSDL as an implementation independent interface that fulfills requirements from many applications. The service code implements the WSDL interface and applies business and mapping logic to call into and map results from backend systems. Since the requestor application is new, it can use the PackageTrackingService interface.
An outbound service is a bus feature that represents an external service on the bus and through which SOAP messages can be sent from the bus out to a Web service provider. Using an outbound service, the bus can call a service implemented according to the SOAP standard and that conforms to the WS-I basic profile on any platform (a non-compliant SOAP service can frequently work with the bus as well, but for our enterprise service to be interoperable and follow best practices, we will conform to WS-I). For example, the service could be implemented in SOAP for CICS®, WebSphere Application Server, or a Perl program. The outbound service in the bus acts as the requestor of the external Web service.
To define an outbound service, you run an outbound service creation wizard in the WebSphere admin console and provide a WSDL document for the external service. The wizard creates one outbound service destination corresponding to the service element in the WSDL, and an outbound port for each port in the WSDL. The outbound service destination represents the Web service on the bus. Other destinations send SOAP messages to that outbound service destination to be sent onto the Web service provider via an outbound port destination. We will go through the wizard details and results later in this article.
The bus supports three protocols for outbound services:
- RMI/IIOP to an EJB.
The WSDL file for the service must have a binding and port definition for each protocol that is to be supported. If multiple ports are available, a default port is specified in the outbound service wizard, and a routing meditation should be provided with logic to select which port is to be used for the message instance (further details on multiple ports and the SOAP/JMS and RMI/IIOP procotol support are beyond the scope of this article).
In Figure 1:
- A SOAP message will be sent into the Service Destination.
- The Service Destination will route it to a Port Destination.
- The Port Destination sends it to the bus Invoker module for the protocol being used (which is not exposed to users).
- The bus Invoker module sends the SOAP message to the Web service provider using the endpoint address in the WSDL file.
Figure 1. Outbound service
An inbound service is a bus feature that accepts a SOAP message sent from a SOAP requestor into the bus. The inbound service may be called just like any other Web service from a variety of platforms. For example, you can still invoke a Web service using a JAX-RPC or .NET® client. An inbound service uses a service destination on the bus (simply a queue destination which acts as the inbound service destination).
To define an inbound service, you run an inbound service creation wizard in the WebSphere admin console, and provide a WSDL file and an existing destination. Each inbound service corresponds to a service element in a WSDL document. We will go through the wizard details and results later in this article.
Back in Part 2, we went through several steps to get the bus ready for Web services, including installing and configuring endpoint listeners. An endpoint listener provides the physical location for a service on the bus to be invoked. SOAP/HTTP and SOAP/JMS are supported, and two listeners for each protocol are provided. Why two for each protocol? This enables an endpoint listener to be configured differently for messages going from an intranet to the Internet, and visa versa -- for example, an HTTP endpoint listener being used for customers sending data into the company can be configured for SSL. Each endpoint has a different URL that will be used by the requestor for that protocol.
In the inbound service wizard, we will specify which endpoint listeners the service will use. An inbound port will be created for each endpoint listener selected. The inbound port equates to the port element in a WSDL document.
In Figure 2:
- A Web service client sends a SOAP message into an Endpoint Listener.
- The Endpoint Listener uses information defined by the inbound port and Inbound Service to send the message to the Service Destination with which the Inbound Service is associated.
- If the service WSDL has a response defined, a Reply Message will be send to a predefined reply queue associated with the Endpoint Listener.
- The Endpoint Listener will wait for the Reply Message and send it back to the client.
Figure 2. Inbound service
Implementing the outbound service
We have defined a WSDL interface for a PackageTrackingService with the operation getPackageStatus, which takes a tracking number string as a parameter and returns a complex type, PackageStatus. The portType code from the WSDL is shown below:
<wsdl:types> <schema targetNamespace="http://service.postrus" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:impl="http://service.postrus" xmlns:intf="http://service.postrus" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <element name="getPackageStatusResponse"> <complexType> <sequence> <element name="getPackageStatusReturn" nillable="true" type="impl:PackageStatus"/> </sequence> </complexType> </element> <element name="getPackageStatus"> <complexType> <sequence> <element name="trackingNumber" nillable="true" type="xsd:string"/> </sequence> </complexType> </element> <complexType name="PackageStatus"> <sequence> <element name="actualDeliveryDate" nillable="true" type="xsd:dateTime"/> <element name="location" nillable="true" type="xsd:string"/> <element name="projectedDeliveryDate" nillable="true" type="xsd:dateTime"/> <element name="status" nillable="true" type="xsd:string"/> </sequence> </complexType> </schema> </wsdl:types> <wsdl:message name="getPackageStatusResponse"> <wsdl:part element="impl:getPackageStatusResponse" name="parameters"/> </wsdl:message> <wsdl:message name="getPackageStatusRequest"> <wsdl:part element="impl:getPackageStatus" name="parameters"/> </wsdl:message> <wsdl:portType name="PackageTrackingService"> <wsdl:operation name="getPackageStatus"> <wsdl:input message="impl:getPackageStatusRequest" name="getPackageStatusRequest"/> <wsdl:output message="impl:getPackageStatusResponse" name="getPackageStatusResponse"/> </wsdl:operation> </wsdl:portType>
A Java™Bean version of the service has implemented the method getPackageStatus, which returns a complex type PackageStatus for tracking numbers 123 and 456, and throws an exception for all other values. This JavaBean has been made into a Web service available over HTTP. This version of the service is provided in the download file included with this article, in the PackageStatusServiceEAR file. For ease of testing, we install the service EAR in the same WebSphere Application Server as the bus.
We are now ready to create the outbound service for our PackageTrackingService. You need to have completed the steps from Part 2 of this series where we create the bus and set up the Web services support. You also need to have a version of a PackageStatus service. If you want to use ours, install the EAR file from the download file into WebSphere Application Server and start the server:
- Open the WebSphere Application Server admin console (the server must be running).
- In the Navigation pane, select Service Integration => Buses.
- Select TheBus.
- In the next window, select Outbound Services. (Figure 3)
Figure 3. Bus configuration
- Select New. In the next steps, the wizard for creating an outbound service will guide us through creating a new outbound service.
- Step 1: Locate the target service WSDL. (Figure 4) Select the URL and provide the location of the WSDL file. For our locally deployed service, the WSDL URL is:
http://localhost:9080/PackageStatusService/ services/PackageTrackingService/wsdl/PackageTrackingService.wsdl. Click Next.
Figure 4. Step 1: Locate the target service WSDL
- Step 2: Select service. (Figure 5) There is only one service in our WSDL. Click Next.
Figure 5. Step 2: Select service
- Step 3: Select ports. (Figure 6) Select the ports that are to be made available as part of the outbound service. We have only one which needs to be checked. If there are multiple ports, one or more need to be checked. Click Next.
Figure 6. Step 3: Select ports
- Step 4: Name the outbound service destinations. Default names are provided for the service, service destination, and port destinations that will be created. but they are fairly awkward names to use especially for the destinations. So we are going to override the default names to makes these elements more usable. Instead, use the following values for these names:
- Outbound service name:
- Service Destination name:
- Port Destination name:
Figure 7. Step 4: Name the outbound service destinations
- Outbound service name:
- Step 5: Select assigned bus members for port destinations. In our case, we have only one of each so accept the defaults, then Finish and Save.
Figure 8. Step 5: Select assigned bus members for port destinations
The outbound service has been created (Figure 9).
Figure 9. Outbound services
Two destinations, one for the outbound service and one for the outbound port have also been created (Figure 10).
Figure 10. Destinations
We can now send a SOAP message conforming to the PackageTrackingService WSDL to the PackageTrackingOutboundService destination and it will be routed through the PackageTrackingOutboundPort port destination to the external service provider.
Our next step is to create our inbound service so the bus can receive the SOAP message from the client application and route it to the outbound service we just created.
Here's a tip:
Here is a useful trick for locating your service's WSDL. To check the deployment of your service in WebSphere Application Server, input a URL of the format:
http://hostname:port/web app context root/services/servicename
where you provide the appropriate values for the items that are bold. For our service, the URL is:
which displays a page that says the service is deployed. If you add
?wsdl to the end of the service URL, as in:
it resolves to the WSDL address URL you should use for your service definitions and displays the WSDL:
Implementing the inbound service
To implement an inbound service, you need to provide a WSDL document and a destination. The inbound service will use the portType and binding in the WSDL document to generate a new WSDL document that has the portType provided, and bindings and the endpoint addresses for the endpoint listeners chosen in the wizard. A destination must already be defined that the inbound service will "use".
In our scenario, we have a choice as to whether we want to reuse the outbound Web service destination for the inbound service destination, or create a new one. If we reuse the outbound destination for the inbound service, the message will automatically flow from the inbound service to the outbound service. However, we can only deploy one mediation per destination (there is flexibility in the mediation model to combine mediation functionality).
The alternative is to create a separate queue destination, assign the inbound service to that destination, and set the forward routing path of that inbound service destination to the outbound service destination. With this design, we can have separate mediations for the inbound and outbound services. Also, this design provides a cleaner separation of concerns. This design to separate the services is what we will implement for our scenario.
We are now ready to create the inbound service for our PackageTrackingService. You need to have completed the steps from Part 2 in which we created the bus and setup the Web services support.
- Open the WebSphere Application Server admin console (the server must be running).
- In the Navigation pane on the left, select Service Integration => Buses => The Bus => Destinations.
- Create a new queue destination named
PackageTrackingDestinationand assign it to your bus member. (Part 3 describes the queue destination creation process.) Select Save.
- Select TheBus, then in the following window, select Inbound Services.
- Click New. The wizard for creating an inbound service will guide us through the creation of a new inbound service.
- Step 1: Select the service destination and template WSDL location. (Figure 11) In our scenario, we are using the same WSDL as we did for the outbound service:
- For Service Destination name, select PackageTrackingDestination.
- For the template WSDL location, enter
- Click Next.
Figure 11. Step 1: Select the service destination
- Step 2: Select service from template WSDL. (Figure 12) There is only one in our WSDL. Click Next.
Figure 12. Step 2: Select service from template WSDL
- Step 3: Name the inbound service and select endpoint listeners. (Figure 13) The inbound service name will be filled in as the destination name appended with InboundService, so ours is: PackageTrackingDestinationInboundService. The list of endpoint listeners comes from the setup steps we did in Part 2. At most you would have two HTTP channels and two JMS channels. We have only installed one HTTP channel, so that is selected as the default. Click Next.
Figure 13. Step 3: Name the inbound service and select endpoint listeners
- Step 4: Define UDDI publication properties. We are not using UDDI, so select Finish and Save.
- Navigate to Buses => The Bus => Inbound Services, and you see the new service PackageTrackingDestinationInboundService displayed (Figure 14).
Figure 14. Inbound services
The inbound service needs to route the SOAP request to the outbound service. This is done using the forward routing path of the inbound service destination, which can be declaratively set in the admin console:
- Select Service Integration => Buses => TheBus => Destinations.
- Click on PackageTrackingDestination.
- At the bottom of the page, enter the forward routing path (Figure 15). The format is
busname:destination, so to route to our outbound service destination, enter
TheBus: PackageTrackingOutboundService. Click OK then Save.
Figure 15. General properties
Publishing the inbound service WSDL
The inbound service wizard generates a new WSDL file for the inbound service that will be used by clients to call the service on the bus. This WSDL combines the portType for the inbound service and the binding and endpoint address of the endpoint listener on the bus. We will export the WSDL for an inbound service:
- Select Service Integration => Buses => TheBus => Inbound Services => PackageTrackingDestinationInboundService.
- On the right, select Publish WSDL files to ZIP file (Figure 16).
Figure 16. Inbound service configuration
- Select PackageTrackingDestinationInboundService.zip and a location to which to save it. (Figure 17)
Figure 17. Publish WSDL files
There are four WSDL files in the zip file. We will use these three WSDL files to create a client:
- TheBus.PackageTrackingDestinationInboundServicePortTypes.wsdl is copied from the WSDL we provided for the inbound service. It makes sense that the inbound service exposes the portType from the WSDL used to create the inbound service.
- TheBus.PackageTrackingDestinationInboundServiceBindings.wsdl defines a standard binding associated with the endpoint listener we chose. It imports the portTypes WSDL. For our service deployed on the SOAPHTTPChannel, the binding is shown here:
<wsdl:binding name="SOAPHTTPChannel1InboundPortBinding" type="impl:PackageTrackingService"> <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getPackageStatus"> <wsdlsoap:operation/> <wsdl:input name="getPackageStatusRequest"> <wsdlsoap:body use="literal"/> </wsdl:input> <wsdl:output name="getPackageStatusResponse"> <wsdlsoap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding>
- TheBus.PackageTrackingDestinationInboundServiceService.wsdl defines the service and port with the endpoint address for the endpoint listener on the bus. It imports the bindings WSDL. For our service deployed on localhost, the service wsdl is shown below. Notice that the address location is an address on the bus, which is generated based on the endpoint listener and inbound service name.
<wsdl:service name="PackageTrackingDestinationInboundService"> <wsdl:port name="SOAPHTTPChannel1InboundPort" binding="sibusbinding:SOAPHTTPChannel1InboundPortBinding"> <wsdlsoap:address location="http://localhost:9080/wsgwsoaphttp1/ soaphttpengine/TheBus/PackageTrackingDestinationInboundService/ SOAPHTTPChannel1InboundPort"/> </wsdl:port> </wsdl:service>
Here's a tip:
There is an undocumented, unsupported handy feature for seeing the inbound service WSDL without doing the export (that may disappear in future releases). In a browser, add
?wsdl to the endpoint address of the service, and the WSDL is displayed. For our service it is:
For the endpoint listener we are using, endpoint address can be figured out based on the pattern of:
and by replacing the values that are bold.
We are now ready to test sending a SOAP request from a SOAP client through the bus to the SOAP provider. The inbound service in the bus may be invoked just like any other Web service from a variety of platforms. The difference is that the SOAP request message will be sent to a destination on the bus, rather than directly to the service. From a development perspective, the client does not know the difference at all. If you have an existing client that calls the Web service, the only change required would be to change the URL address from the real service to the service in the bus.
In our case, we used IBM Rational Application Developer V6 to create a WebSphere JAX-RPC client using the WSDL exported in the previous step. (This client code is available in the download file.) For ease of testing, we install the client EAR, PackageStatusClientEAR.ear, in the same WebSphere Application Server as the bus.
To run test our configuration with our client:
- Stop and restart the server.
- In a browser, type the client URL:
- Select getPackageStatus.
- Enter a valid value of
456, then select Invoke.
You should see information about the package returned to the client JSP. If you enter a different value, a SOAP fault will be returned.
In Part 5 of this article series, we described the Web services support available for building an Enterprise Service Bus with WebSphere Application Server V6 Messaging Resources. We demonstrated creating an inbound service and an outbound service with the same WSDL, routing from the inbound service to the outbound service, and testing our configuration. In this scenario, the SIBus is acting as a SOAP proxy and the ESB functionality provided is that of endpoint transparency; that is, the actual service endpoint is hidden from the client.
|Code sample||reinitz_esb_part5_code.ZIP ( HTTP | FTP )||50 KB|
- Building an Enterprise Service Bus with WebSphere Application Server V6: Part 1. Introduction to WebSphere V6 Messaging Resources
- Building an Enterprise Service Bus with WebSphere Application Server V6: Part 2. Business requirements and the bus
- Building an Enterprise Service Bus with WebSphere Application Server V6: Part 3. A simple JMS messaging example
- Building an Enterprise Service Bus with WebSphere Application Server V6: Part 4. Building a better bus with mediations
- Get involved in the developerWorks community by participating in developerWorks blogs.
- Browse for books on these and other technical topics.