From the IBM WebSphere Developer Technical Journal.
If you have read the previous articles in this series, then you will be familiar with creating and using message mediations, a new programmatic extension to the messaging capabilities of IBM WebSphere Application Server V6, that can simplify connecting systems, services, applications, or components that use messaging. These, along with other recent articles by IBM colleagues, have focused primarily on the one-way messaging paradigm. However, it is also common for Java™ Messaging Service (JMS) and other applications to implement request/response style semantics. The JMS specification even provides the QueueRequestor and TopicRequestor classes to simplify this dynamic messaging. In Part 5 of this series, we will explain how to use message mediations to handle request/response messages.
For the purpose of this article, the application example we will look at is a stock inventory management system that sends queries to determine the quantity of an item that is in stock in a warehouse. The information to answer the query will be sent in a response. This article reuses the mediation written for Part 4: Modifying messages with mediations and XSLT.
Let's begin by reviewing what we mean by a mediation and a message format in the context of WebSphere Application Server.
Several sorts of messages can be given to a mediation handler. The mediation handler determines what sort of message it has been given by using the getFormat method to obtain the message format. Possible values of the format include:
| Format | Description |
|---|---|
| JMS:byte | JMS message containing a byte array. |
| JMS:text | JMS message containing a string. |
| JMS:object | JMS message containing an byte array that can be deserialized into an object using a java.io.ObjectInputStream. |
| JMS:stream | JMS message containing a stream of typed data. |
| JMS: | JMS message with no content (created by constructing a javax.jms.Message object rather than any specific JMS message type). |
| SOAP: | SOAP message to or from a Web service. |
| Bean: | Message to or from a Web service. |
Request/Response processing in messaging
Messaging providers do not typically provide direct support for request/response messaging, but there are three conventions which are generally used:
Use temporary reply queue. In this model, the requester creates a temporary destination, puts the address of the response destination into the request message, and then sends it. The responder then sends the response to that destination. This model is commonly used by JMS applications, and has the disadvantage that to correlate individual requests with responses, it is necessary to use a temporary destination per request. To work around this limitation, it is common to use a single temporary destination per client and then use the mechanism described in the next two points to correlate individual requests and responses.
Copy Message ID to Correlation ID. In this model, the requesting application listens on a well known queue for a response. This queue is either known by both the requester and the responder, or the requester specifies in the request message where to send replies. The responding application then copies the message ID of the request into the correlation ID of the response. The requester then uses this in the correlation ID to filter the response. This model is used by the inbound, outbound, and gateway service functions in the service integration bus. It is also commonly used by WebSphere MQ applications.
Copy Correlation ID to Correlation ID. This model is identical to the previous model, except that the requester adds a correlation ID to the request message. The responder then copies the correlation ID of the request message into the correlation ID of the response message. This is commonly used by WebSphere MQ applications.
Request/Response processing in a bus
The bus itself does not have direct support for request/response processing, but does provide support upon which request/response processing can be easily built.
Each message contains it a list (or path) of destinations that the message should visit as it progresses through the bus. This is known as the forward routing path, and typically a request message will be sent with a path containing a single destination. Additionally, a destination can be configured with a default forward routing path, which will be put into a request message if it arrives at the destination without a forward routing path.
A message also contains a reverse routing path. Although this is not processed as a message goes through the bus, this path would typically be taken from the request message and set as the forward routing path of the response message. In this way, the route that the response message takes as it travels through the bus can be affected by the processing of the request message.
If a response is expected, then the request message will have a reverse routing path set. Each destination can have a reply destination specified. This destination will be prepended to the reverse routing path (if one already exists) as the message travels through that destination.
Mediating request/response messaging
As a general rule, mediating request/response message interactions in the bus is not that much more difficult than mediating a one-way message. If you need to mediate a request message, some form of mediation will probably be required on the response path. A simple example is the transformation of a message from a COBOL copybook to XML; if the responder only understands XML and the requester only understands COBOL, then both the request and response message will need to be transformed.
When mediating a request message, there are a number of ways a response mediation can be applied, if one is needed:
Create a mediation that understands whether the message is a request or response, and acts appropriately. The destination on which the mediation is applied could be added to the request message's reverse routing path. This would mean that the response message would travel back via the mediation's destination.
Create two mediations could be created: a request mediation and a response mediation. These are applied to two different destinations. The request message goes through one and the response message goes through the other. Either the request message could simply add the response mediation's destination to the reverse routing path, or simply apply the reverse mediation to the reply destination.
Create a single mediation that does not understand the difference. In this case, the same mediation can be applied to the request and response path and will perform the same logic, but can be parameterised based on the destination to which it is deployed.
The simplest of these to implement is the last, the most complex is the first. By making use of the reply destination field on a destination, the request mediation does not need to do anything to have the response routed to its companion response destination. This is especially useful if you have a generic mediation, such as an XSLT mediation that needs to be applied to perform a different XSLT mediation on the request and response legs.
It is important to choose an appropriate request/response model for your application and environment. For the purpose of this article, we will be using a combination of the first and second models, listed above. In our model, the client will create a temporary destination for all its requests, and will correlate the individual requests and responses by copying the message ID to the correlation ID.
We will go through a relatively simple example of request/response mediations, showing how it can be performed without writing any code. The redbook Patterns: SOA with an Enterprise Service Bus in WebSphere Application Server V6 gives details on more complex examples of aggregating and disaggregating messages.
The example will make use of a simple JMS application to provide the requesting client and the responding service. It is likely in a real world solution that the responding application is some form of enterprise application distinct from the client.
The JMS application sends a JMS BytesMessage to the requestQueue with the XML shown in Listing 1.
Listing 1. Example XML document produced by JMS client
<?xml version="1.0" encoding="utf-8"?>
<stockQuery>
<item number="1234"/>
</stockQuery>
|
The responding part of the JMS application requires that the XML be in the format shown in Listing 2.
Listing 2. Example XML document as required by responding JMS application
<?xml version="1.0" encoding="utf-8"?>
<stockQuery>
<item>1234</item>
</stockQuery>
|
The request message will need to be transformed before it gets to the responding application. The XSLT shown in Listing 3 will perform the transformation.
Listing 3. The XSLT used to translate the two request XML documents
<?xml version="1.0" encoding="utf-8"?> <stockQuery xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xslt:version="1.0"> <item><xslt:value-of select="/stockQuery/item/@number"/></item> </stockQuery> |
The responding JMS application sends the response in a JMS BytesMessage to the JMSReplyTo specified in the request message. It puts the XML shown in Listing 4 into the response message.
Listing 4. Example XML document produced by responding application
<?xml version="1.0" encoding="utf-8"?>
<stockAvailability>
<quantity>2</quantity>
</stockAvailability>
|
The client part of the JMS application requires the XML to be in the format shown in Listing 5.
Listing 5. Example XML document required by requesting application
<?xml version="1.0" encoding="utf-8"?>
<stockAvailability>
<item quantity="2"/>
</stockAvailability>
|
The response message will need to be transformed before it gets to the client application. The XSLT shown in Listing 6 will perform the transformation.
Listing 6. The XSLT used to translate the two response XML documents
<?xml version="1.0" encoding="utf-8"?> <stockAvailability xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xslt:version="1.0"> <item><xslt:attribute name="quantity"><xslt:value-of select="/stockAvailability/quantity"/></xslt:attribute> </item> </stockAvailability> |
This example is, of course, trivial and in a real world application a more substantial conversion is required. For example SOAP to COBOL copybook on the request and COBOL copybook to SOAP on the response.
Simple request/response mediation
Here, we will demonstrate how to build request/response mediations, and, specifically, how it is possible to build these mediations without writing any code.
This example requires that certain resources be created up front, which can be done simply by using the supplied createInitialResources.jacl script included in the download material. This script will create the resources listed in these tables:
A bus will be created with a single bus member:
| Field | Value |
|---|---|
| Name | dwBus |
Two queue type destinations will be created in separate objects:
| Field | Value |
|---|---|
| Identifier | dwRequestQueue |
| Identifier | dwResponseQueue |
A single mediation:
| Field | Value |
|---|---|
| Name | dwXSLTMediation |
| Mediation handler list name | dwXSLTMediation |
The destinations dwRequestQueue and dwResponseQueue are then mediated using dwXSLTMediation.
For the supplied JMS application, the following JMS resources will be defined using the default messaging provider.
JMS connection factory:
| Field | Value |
|---|---|
| Name | dwCF |
| JNDI Name | jms/dw/CF |
| Bus Name | dwBus |
JMS queue:
| Field | Value |
|---|---|
| Name | dwDest |
| JNDI Name | jms/dw/dest |
| Bus Name | dwBus |
| Queue Name | dwRequestQueue |
Configuring for request/response processing
We now have our initial configuration setup that we can modify to enable request/response processing. (To create the basic resources, see the previous articles in this series, listed in Resources.)
The first change is to set the reply destination name on the request destination:
- From the WebSphere Application Server administrative console, expand Service integration => Buses.
- Select the bus dwBus.
- Under Destination Resources select Destinations.
- Select the destination dwRequestQueue.
- Scroll down until the Reply destination field is visible and enter
dwResponseQueueas shown in Figure 1.
Figure 1. Configuring a reply destination
- Click OK.
This next step is to configure the XSLT mediation so it applies the proper transformation. The XSLT applied by the mediation can be specified using either mediation context properties or destination context properties. These properties are set in the administrative console on the destination or mediation. They are then placed into the SIMediationContext as properties. For this example, the same mediation is applied to two different destinations where each destination needs a different XSLT to be applied. This means that the destination context properties are the appropriate places to specify this information.
- From the administrative console, expand Service integration => Buses.
- Select the bus dwBus.
- Under Destination Resources select Destinations.
- Select the destination dwRequestQueue.
- Select the link Context Properties.
- Click New.
- Enter or select the following values (Figure 2):
- Name:
Stylesheet - Context type: String
- Context value:
<?xml version="1.0" encoding="utf-8"?><stockQuery xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xslt:version="1.0"><item><xslt:value-of select="/stockQuery/item/@number"/></item></stockQuery>
Figure 2. Configuring the request mediation XSLT
- Name:
This also needs to be done for the response destination specifying the second XSLT.
- From the administrative console, expand Service integration => Buses.
- Select the bus dwBus.
- Under Destination Resources, click Destinations.
- Select the destination dwResponseQueue.
- Select the link Context Properties.
- Click New.
- Enter or select the following values (Figure 3):
- Name:
Stylesheet - Context type: String
- Context value:
<?xml version="1.0" encoding="utf-8"?><stockAvailability xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xslt:version="1.0"><item><xslt:attribute name="quantity"> <xslt:value-of select="/stockAvailability/quantity"/> </xslt:attribute></item></stockAvailability>
Figure 3. Configuring the response mediation XSLT
- Name:
The XSLT mediation used by this application is a slight modification to the mediation provided in the previous article, which performed the XSLT on a copy of the message. The mediation used in this example performs the XSLT on the message being mediated. The code shown in Listing 7 replaces the code in the innerHandle method of the XSLTMediationHandler class. This mediation is stored in the MediationPart5MediationEAR.ear file, included in the download material, and needs to be installed into the server.
Listing 7. The content of the modified innerHandle method
// Retrieve the message from the context
SIMessage message = getContext().getSIMessage();
// Get the message contents in the form of a JMS Bytes message
try
{
// Get a new datagraph for the new message we're about to build - Point 1
DataGraph graph = message.getNewDataGraph(SIApiConstants.JMS_FORMAT_BYTES);
DataObject body = graph.getRootObject();
if (body.isSet("data"))
{
// Grab the bytes
byte[] payload = body.getBytes("data/value");
// Transform the bytes
payload = XSLTTransform.transform(payload,getStringProperty(STYLESHEET_PROPERTY_NAME));
// Replace the payload in the data graph
body.setBytes("data/value",payload);
message.setDataGraph(graph, SIApiConstants.JMS_FORMAT_BYTES);
}
else
{
// No bytes sent, so throw an IllegalArgument so that the message
// will be sent to the exception destination
IllegalArgumentException e = new IllegalArgumentException("No body to the message");
throw e;
}
}
catch(Exception e)
{
// Hmm, we had a problem somewhere doing the transformation or maybe the send
e.printStackTrace();
throw new MessageContextException(e);
}
// If we get here, everything worked and the tracking message has been sent
return true;
|
Before running the application, it is important to save the configuration and restart the application server. After this has been done, run the sample application by executing this command: launchClient.bat MediationPart5ClientEAR.ear 5. This should result in the output shown in Listing 8.
The test application is a simple JMS application that acts both as the client and the server, and takes a single number as an argument.
Listing 8. Output from running the test application
IBM WebSphere Application Server, Release 6.0 J2EE Application Client Tool Copyright IBM Corp., 1997-2004 WSCL0012I: Processing command line arguments. WSCL0013I: Initializing the J2EE Application Client Environment. WSCL0035I: Initialization of the J2EE Application Client Environment has completed. WSCL0014I: Invoking the Application Client class mediation.messages.part5.Main Sending request message: <?xml version="1.0" encoding="utf-8"?> <stockQuery> <item number="5" /> </stockQuery> Received request message:<?xml version="1.0" encoding="UTF-8"?><stockQuery> <item>5</item></stockQuery> Sending response message: <?xml version="1.0" encoding="utf-8"?> <stockAvailability> <quantity>2</quantity> </stockAvailability> Received response message: <?xml version="1.0" encoding="UTF-8"?> <stockAvailability><item quantity="2"/></stockAvailability> |
Correlating requests and responses
So far, we have discussed a simple case where the action the response takes is dependent only on the content of the response message. There are cases where this may not be possible, such as if a request message is sent to the bus, is mediated, and then transfered to a WebSphere MQ queue manager; in this case, the reverse routing path is not likely to be maintained, but this is needed for the response to be correctly handled by the bus. Another example is in aggregating and disaggregating messages: if a single message is disaggregated into several messages and a single response is necessary, it must be known when all the responses have been received.
In these cases, it is necessary to store additional information about the request message so it can be seen by the response mediation. This is refered to as correlation. There are two simple ways of storing this correlation information so it can be used from within a mediation.
- Use a database
- Use a side queue.
Both mechanisms are commonly used and which one is best will depend on the specifics of the message interactions.
A side queue is a simple, quick, and effective mechanism for storing data, and has these advantages:
- Simple administration.
- The mediation API provides mechanisms for sending and receiving messages.
- If using transactions, one-phase optimisations are possible.
- The bus can automatically expire the data when it is no longer valid.
And these disadvantages:
- Message selection does not perform as well as a database SQL selection, especially when the queue has a large number of messages.
- When a side queue is localised to a clustered bus member with multiple messaging engines, care must be taken to ensure the correlation information is on the queue point accessed by the response mediation.
A database is a powerful mechanism for storing the data, and has these advantages:
- The correlation information can be easily shared with applications.
- A database should scale better if a lot of correlation data is stored.
- A database should scale better if message throughput is high.
And these disadvantages:
- Some mechanism of expiring old data may be required for lost responses.
- When using transactions, a two-phase commit is required.
- Requires more configuration than a side queue.
This article detailed how to mediate request/response interactions using the extended messaging capabilities of WebSphere Application Server V6, and discussed some of the more advanced issues involved in correlating requests and responses.
I would like to thank Daniel Murphy and David Vines for their help in writing and reviewing this article.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample application files | mediationpart5.zip | 30 KB | FTP |
Information about download methods
Learn
-
A practical introduction to message mediation series:
- Part 1: The basics of message mediation
- Part 2: Routing messages with mediations
- Part 3: Modifying messages with mediations
- Part 4: Modifying messages with mediations and XSLT
-
Introduction to Service Data Objects
-
Patterns: SOA with an Enterprise Service Bus in WebSphere Application Server V6
Get products and technologies
-
Download a free trial version of
WebSphere
Application Server Version 6.0.
-
Download a free trial version of IBM Rational Application Developer
-
Build your next development project with
IBM
trial software, available for download directly from developerWorks.





