Prescriptive Architecture
Implementing Asynchronous Interoperability
 

Patterns and Practices home

Microsoft Corporation

December 2003

Summary: Interoperability using messaging components in the Data Resource tier. Taking the XBikes sample code, it shows how you can use Messaging components such as Microsoft Message Queue or Java Messaging Service implementations to connect to message queues, providing asynchronous operation, providing support for transactions and long running operations.

Contents

Introduction

Determine Data Exchange Formats and Data Types

Designing and Building the Service Interface

Designing and Building the Asynchronous Interoperability Adapters

Using the MSMQ-MQSeries Bridge

Using JNBridgePro

Using Ja.NET

Summary

References

Introduction

Implementing asynchronous interoperability is the third interoperability scenario introduced in Chapter 1, "Introduction," involving the connection of .NET Framework components to message queuing components in the Data tier. Asynchronous interoperability covers situations where you want a client application to be able to make a call to another tier or process. Having made the call, the client can then continue to operate while the remote component processes the request rather than wait for the result.

Using asynchronous operations only makes sense for tasks that are amenable to this style of operation. In the sample XBikes application, the process of placing an order is a good candidate for using message queues and is recommended best practice for business to consumer e-commerce applications.

The main focus of this chapter is on connecting to IBM WebSphere MQ. Another section reviews the MSMQ-MQSeries Bridge that ships with Microsoft Host Integration Server (HIS) and provides a bridge between Microsoft Message Queuing (MSMQ) and IBM WebSphere MQ (formerly known as MQSeries).

The section on JNBridgePro covers how you can generate Java proxy assemblies that bridge the connection between the .NET Framework Business tier components and WebSphere MQ. The chapter finishes with a section that shows the same technique using Ja.NET.

Determine Data Exchange Formats and Data Types

Like with the other interoperability technologies, you first have to decide upon a data format that both .NET Framework and Java can understand. This choice is dependent on a number of factors:

  • How are you going to integrate with the message queues?
  • Are you using a bridging product to wrap message queue functionality?
  • Are you using the MSMQ-MQSeries Bridge?

Your choice of data exchange format and data types depends on which integration technology you use:

  • If you are using one of the bridging products to wrap the message queue functionality, you are likely to use the same data exchange format and data types as you used for point-to-point communication.
  • If you use the MSMQ-MQSeries Bridge, you have to implement a similar strategy to Web services. In order to allow objects to be read from and written to the message queues you must serialize these XML documents into strings. XML-formatted strings preserve the richness of information contained in .NET Framework or Java objects and they overcome the interoperability difficulties that arise when exchanging real objects.

This chapter describes each of these options.

Designing and Building the Service Interface

When using message queuing for asynchronous interoperability, there are no direct calls into service interfaces across technological boundaries. Instead, the role of service interfaces is more like "message consumers." The service interface is an application that monitors and picks up messages from a queue, unpacks the data, and sends it to the existing facade or application that processes the message.

Both .NET Framework and J2EE provide built-in support for activation of components from messages (queued components in .NET Framework and message-driven beans in J2EE). However, there are differences in the required message structure in each case, so this approach is not feasible when you require interoperability between .NET Framework and J2EE. Instead you write a service interface yourself that consumes messages and passes them on to the appropriate service facade.

Building a message consumer is an easy task. Regardless of the technology that you use to write the message, the technique for consuming the message is the same. You need to create a client application or service that polls for messages on the queues and reads any messages found. The data you extract from the message is then either already in the correct format (if it uses the bridging technologies) or requires de-serializing from an XML string back into the correct data class using the techniques described for Web services in Chapters 7 and 8.

Figure 9.1 shows the role of service interfaces in asynchronous communications.

ms998432.j2ee_interop_c9_fig9-1(en-us,MSDN.10).gif

Figure 9.1: The role of service interfaces in asynchronous communications

After the data is back into the correct format, all you need is a method call into the appropriate service facade.

Designing and Building the Asynchronous Interoperability Adapters

Building the asynchronous interoperability adapters is a similar process to building a synchronous adapter, except that instead of making calls to the correct service interface, you place a message in a message queue. Again, depending on the technology in use, you may have to manipulate the data, either by converting it into the Java data proxies or by serializing it into a string as XML.

Figure 9.2 shows the role of interoperability adapters in asynchronous communications.

ms998432.j2ee_interop_c9_fig9-2(en-us,MSDN.10).gif

Figure 9.2: The role of interoperability adapters in asynchronous communications

How the message joins the message queue depends upon the technology used. For bridging products that wrap the JMS functionality, you can place the messages in the queue using ObjectMessage types; otherwise, you have to use text-based message types.

Using the MSMQ-MQSeries Bridge

If you are familiar with code that writes messages from .NET Framework to MSMQ and have experience of writing JMS code to work with WebSphere MQ, enabling interoperability using the MSMQ-MQSeries Bridge is straightforward.

MSMQ-MQSeries Bridge requires two computers, the first with the following configuration:

  • Windows 2000 or Windows 2003
  • Active Directory
  • MSMQ-MQSeries Bridge
  • MSMQ (with routing support)
  • WebSphere MQ client

The second computer should have Windows 2000 installed as a member server and should be running WebSphere MQ.

You need to configure the computer running WebSphere MQ as the foreign computer in MSMQ. Do this by creating a foreign site under the Services/MsmqServices node in Active Directory Sites and Services, add a new MSMQ routing link to link the local site (usually Default-First-Site-Name) to the foreign site, add the MSMQ computer as the local site gate, and then add the MQ Series computer as a foreign computer to the foreign site.

For more information about the details of configuring MSMQ foreign sites, see "Configuring cross-platform messaging" on TechNet.

For more information about how to configure and use the MSMQ-MQSeries Bridge, see "Chapter 13 — MSMQ-MQSeries Bridge Configuration Guide" on TechNet.

Consider the scenario where you are reading WebSphere MQ messages using JMS. Originally, those messages came from MSMQ and passed over the bridge. In this case, there should be no message consumption problems providing you change the WebSphere MQ JMS configuration. To implement this interoperability scenario, set the Queue Configuration for WebSphere MQ's targetClient to MQ, not JMS. If you do not make this change, WebSphere MQ expects a JMS headed message, which .NET Framework cannot generate.

Note   Do not configure targetClient on existing queues, because the change may cause existing JMS applications to fail. Always create a new message queue exclusively for interoperability purposes.

In the reverse direction, providing you change the targetClient to MQ, you can generate messages from JMS and then pass them over the bridge and consume them in a .NET Framework application.

Configuring the Message Queues

To enable interoperability through the MSMQ-MQSeries Bridge, you need to create two queues for each direction in which you want to send messages. You need to define local queues for receiving messages and remote queues for sending messages. You also have to configure the bridge correctly.

Figure 9.3 shows how you might set up two queues for each direction you want to send messages between .NET Framework and Java.

ms998432.j2ee_interop_c9_fig9-3(en-us,MSDN.10).gif

Figure 9.3: Logical representation of the MSMQ-MQSeries Bridge connecting MSMQ and MQ Series

Start by defining the MSMQ queues. You add a local queue to the computer running the bridge and a remote queue on the foreign computer.

Next, using the MSMQ-MQSeries Bridge Manager, you add a MQI channel which points to the computer running WebSphere MQ. This creates four message pipes, two transactional and two non-transactional, that route messages between the two queuing systems. After you have created these, you need to export both the client and server definitions. Copy these files to the WebSphere MQ computer, and then import them using the runmqsc command. This command configures the transmission queues and keeps the channels synchronized across the bridge.

The next step is to create a local and remote queue in WebSphere MQ. Configure the remote queue to point to the MSMQ queue through the bridge. Do this by configuring the remote queue manager name and transmission queue name to point to the objects that the import created.

Finally, you need to copy the WebSphere MQ Client Channel Table file from the computer running WebSphere MQ to the MSMQ computer and configure the MQCHLLIB and MQCHLTAB environment variables to point to this file.

Selecting a Data Format

When sending messages on queues using the MSMQ-MQSeries Bridge, you must ensure that the receiving end can consume the message data. The only realistic way of sending complex data between J2EE and .NET Framework is to serialize the data into an XML-formatted string. Additionally, WebSphere MQ supports sending TextMessages, where you load up the body with a string containing the XML data you want to send. MSMQ also allows you to send simple messages containing an XML-formatted string.

Note   It is not feasible to use other data types because of binary serialization differences between .NET Framework and J2EE as discussed in Chapter 3, "Interoperability Fundamentals."

Creating the Message Consumer

This guide has already covered how the Message Consumer is an application that you create to poll and read messages from a queue and place them into the resource facade. Because you are using the bridge, you work with XML-formatted strings. Therefore, you have to reconstruct the data from the XML string before you can use it to call methods on the resource facade. The next two sections consider how to do this on the two platforms.

Creating the .NET Framework Message Consumer

As described in Chapter 5, "Interoperability Technologies: Resource Tier "the .NET Framework message consumer reads from an MSMQ queue. After you read the contents of the message you must reconstruct the data. For techniques about how to do this, see the "Web Services" section of Chapter 7, "Integrating .NET in the Presentation Tier."

The following code sample shows how to read a message from MSMQ and the data you use to build the correct .NET Framework data type.

MessageQueue q = new MessageQueue(_queueName);
q.Formatter = new XmlMessageFormatter( new Type[] {typeof(String)} );
Message order = q.Receive(0);
string xml = (string) order.Body();
StringReader sr = new StringReader(xml);
OrderData ds = new OrderData();

// Load result string back into an OrderData-typed DataSet
ds.ReadXml(sr);
Note   The preceding sample uses the OrderData custom data type from XBikes. However, the XBikes application does not implement this code.

Creating the J2EE Message Consumer

The J2EE message consumer reads from WebSphere MQ, which you can build using either the MQI Java classes or JMS. After you read the message, you have to reconstruct the Java data from the XML string. For techniques about how to do this, see the "Web Services" section of Chapter 8, "Integrating .NET in the Business Tier."

The following code sample shows how you can read a message from WebSphere MQ and the data you use to build the correct J2EE data type.

String connectionName = "XBikesQFC";
InitialContext ic = new InitialContext();
QueueConnectionFactory factory =
       (QueueConnectionFactory) ic.lookup(connectionName);
QueueConnection connection = factory.createQueueConnection();
QueueSession session =
connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) ic.lookup(queueName);
QueueReceiver receiver = session.createReceiver(queue);
connection.start();

TextMessage message = (TextMessage) receiver.receive();
String orderXML = message.getText();
OrderData order = OrderConverter.stringtoOrderData(orderXML);
DalServiceFacade facade = getFacadeHome().create();

return facade.saveOrder(order);
Note   The preceding sample uses the OrderData custom data type, and the OrderConverter class from XBikes. However, the XBikes application does not implement this code.

Creating the Interoperability Adapter

Following the techniques already discussed in this guide, it is recommended that you create an asynchronous interoperability adapter to provide access to the asynchronous communication channel. This adapter serializes the data for the message into an XML formatted string.

Creating the .NET Framework Asynchronous Interoperability Adapter

The .NET Framework application sends a message to MSMQ, so you can use the .NET Framework classes to do this, as discussed in Chapter 5. Because the final destination of the message is to WebSphere MQ, you must write the message as a string.

If you are using datasets, you can extract the XML using the GetXml() method. You can then place the XML string in the MSMQ message queue as the following code example shows.

string xml = order.GetXml();
MessageQueue q = new MessageQueue(_queueName);
q.Send(xml);
Note   The preceding sample uses the OrderData class from the order object that appears in the XBikes application. However the XBikes application does not implement this code.

Creating the J2EE Asynchronous Interoperability Adapter

The J2EE application sends a message to WebSphere MQ, so you can use the JMS classes (or MQI) to send the message. Again, because the final message destination is MSMQ, you must create a string message rather than writing an object.

For the background and code for serializing Java data to an XML string, see the "Web Services" section of Chapter 7. To send the message, you can use JMS code similar to the following example.

InitialContext ic = new InitialContext();
QueueConnectionFactory factory =
    (QueueConnectionFactory) ic.lookup("XBikesQCF");
QueueConnection connection = factory.createQueueConnection();
QueueSession session =
    connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) ic.lookup("XBikesQ");
QueueSender sender = session.createSender(queue);
sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
sender.setPriority(4);
sender.setTimeToLive(0);
connection.start();

// Use a text message
TextMessage message = session.createTextMessage();

// Convert the order to a string
String sorder = OrderConverter.orderListDataToString(orderObject);
message.setText(sorder);
sender.send(message);
Note   The preceding sample uses the OrderData and OrderConverter classes from XBikes. However, the XBikes application does not implement this code.

Now that how to implement the MSMQ-MQSeries Bridge has been described, it is time to look at runtime bridges for asynchronous interoperability.

Using JNBridgePro

Chapter 4, "Interoperability Technologies: Point to Point," shows how JNBridgePro lets you create .NET Framework proxies for Java classes. These .NET Framework proxies allow your .NET Framework application to interact with the native Java classes. One technique of providing asynchronous interoperability is to create proxy classes for the JMS classes on Java. This technique provides the ability to make JMS message calls from .NET Framework. This solution is somewhat different to those discussed so far, because .NET Framework would not be directly interacting with the message queues; it would be communicating through Java. Therefore, you need a running J2EE application server to provide .NET Framework with JMS access.

Figure 9.4 shows the role of JNBridge in asynchronous communications.

ms998432.j2ee_interop_c9_fig9-4(en-us,MSDN.10).gif

Figure 9.4: The role of JNBridge in asynchronous communications

Note   Because JNBridgePro wraps JMS, there is no special configuration required other than configuring the JMS support for WebSphere MQ.

Deciding on a Data Format for JNBridgePro

JNBridgePro wraps the JMS functionality, allowing you to place a Java object directly into the message queue. The only task from a data perspective is to create a .NET Framework proxy of the Java data object, populate this with the data from .NET Framework, and then use this object to write the message.

Creating the Message Consumer for JNBridgePro

Because the JNBridgePro adapter places a JMS message in WebSphere MQ, you can use standard JMS code for reading the message. JMS with a JNBridgePro wrapping determines the format of the message you read, so there is no need to change the data that you can send directly to the resource application. The following code example shows how to read the message from JMS.

InitialContext ic = new InitialContext();
QueueConnectionFactory factory = (QueueConnectionFactory) ic.lookup(connectionName);

QueueConnection connection = factory.createQueueConnection();
QueueSession session =
connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) ic.lookup(queueName);
QueueReceiver receiver = session.createReceiver(queue);
connection.start();

ObjectMessage message = (ObjectMessage) receiver.receive();
order = (OrderData) message.getObject();
DalServiceFacade facade = getFacadeHome().create();

return facade.saveOrder(order);

Creating the Asynchronous Interoperability Adapter for JNBridgePro

To create the asynchronous interoperability adapter, you need to expose the JMS classes from J2EE into the .NET Framework application. You can do this using the JNBridgePro proxy generation tool, in the same way that you used it to achieve interoperability as described in Chapter 7.

To create the proxy, add the j2ee.jar, jndi.jar, and jms.jar packages as well as any application-specific data classes you require to the JNBridgePro classpath. You must create proxies for the following classes:

  • javax.naming.InitialContext
  • javax.naming.NamingException
  • javax.jms.QueueConnectionFactory
  • javax.jms.QueueConnection
  • javax.jms.QueueSession
  • javax.jms.Session
  • javax.jms.Queue
  • javax.jms.QueueSender
  • javax.jms.ObjectMessage
  • javax.jms.JMSException
  • javax.jms.DeliveryMode
  • javax.jms.InvalidDestinationException

In the XBikes sample application, this list also included the classes from the xbikes.common.data package.

After you generate the proxy and configure the .NET Framework application, the .NET Framework interoperability adapter calls the proxy classes in a similar way that the J2EE application would use them. The following code sample shows how to create a new JMS message in WebSphere from .NET Framework.

InitialContext ic = new InitialContext();
QueueConnectionFactory factory =
(QueueConnectionFactory) ic.lookup(connectionName);

QueueConnection connection = factory.createQueueConnection();
connection.start();
QueueSession session =
connection.createQueueSession(false,    SessionConstants.AUTO_ACKNOWLEDGE);
javax.jms.Queue queue = (javax.jms.Queue) ic.lookup(queueName);
QueueSender sender = session.createSender(queue);

ObjectMessage message = session.createObjectMessage(order);
sender.send(message);
Note   This it is almost identical to sending a JMS message from Java, but the language is C#.

The next section covers the same techniques but using Ja.NET instead of JNBridgePro.

Using Ja.NET

Chapter 4 shows how Ja.NET lets you to define .NET Framework proxy classes for Java classes, to enable .NET Framework applications to access Java classes. In a similar way, you can define .NET Framework proxy classes for the Java JMS classes to enable .NET Framework applications to make JMS message calls. This solution is somewhat different to those discussed so far, because the .NET Framework application is communicating through Java rather than interacting directly with the message queues. This implementation requires that you run a J2EE application server to provide .NET Framework with JMS access.

At first sight, this looks the same as the JNBridgePro solution; however, Ja.NET comes supplied with a ready-built JMS proxy. This is because all JMS invocations are implemented through interfaces. Hence you do not need to create a proxy yourself when you use Ja.NET.

Figure 9.5 shows the role of Ja.NET in asynchronous communications.

ms998432.j2ee_interop_c9_fig9-5(en-us,MSDN.10).gif

Figure 9.5: The role of Ja.NET in asynchronous communications

Again, you need to configure message queues and decide on a data format.

Configuring the Message Queues

Because Ja.NET provides a wrapper for JMS, there is no special configuration required. However, you still need to configure WebSphere MQ for JMS support.

Deciding on a Data format for Ja.NET

Because Ja.NET wraps the JMS functionality, you can place a Java object directly into the message queue. The only task from a data perspective is to create a .NET Framework proxy of the Java data object, populate this with the data from .NET Framework, and then use this object to write the message.

Creating the Message Consumer for Ja.NET

Because the Ja.NET adapter places a JMS message in WebSphere MQ, you can use standard JMS code for reading the message. The message is in JMS format with a Ja.NET wrapper, so there is no need to change the data. Thus you can send it directly to the resource application. The following code sample shows how to read the message from JMS.

InitialContext ic = new InitialContext();
QueueConnectionFactory factory = (QueueConnectionFactory) ic.lookup(connectionName);

QueueConnection connection = factory.createQueueConnection();
QueueSession session =
connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) ic.lookup(queueName);
QueueReceiver receiver = session.createReceiver(queue);
connection.start();

ObjectMessage message = (ObjectMessage) receiver.receive();
order = (OrderData) message.getObject();
DalServiceFacade facade = getFacadeHome().create();

return facade.saveOrder(order);

The next section looks at creating the asynchronous interoperability adapter.

Creating the Ja.NET Asynchronous Interoperability Adapter

To create this adapter, use the prepackaged JMS proxy that ships with Ja.NET 1.5. This proxy is strong named so you can use it from within a COM+ context without problems. You also have to create proxy classes for any Java data types you want to access from .NET Framework. Remember to package the data into the Java classes before placing the message in the queue.

Note   Chapter 7 contains details for generating proxies for Ja.NET.

The following code sample shows how to send a message from .NET Framework to a JMS queue using Ja.NET.

JNDIContext context = new JNDIContext();
object o = context.Lookup("javax.jms.QueueConnectionFactory", "XBikesQCF");
javax.jms.QueueConnectionFactory factory =
    (javax.jms.QueueConnectionFactory) o;
QueueConnection connection = factory.createQueueConnection();
QueueSession session =
    connection.createQueueSession(false, SessionConstants.AUTO_ACKNOWLEDGE);
javax.jms.Queue queue =
(javax.jms.Queue) context.Lookup("javax.jms.Queue", "XBikesQ");
QueueSender qSender = session.createSender(queue);
qSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
qSender.setPriority(4);
qSender.setTimeToLive(0);
connection.start();

ObjectMessage message = (ObjectMessage)session.createObjectMessage();
message.setObject(ejbOrder);
qSender.send(message);

Again, this is almost identical to sending a JMS message from Java, but the language is C#.

Summary

This chapter described mechanisms for connecting from a .NET Framework Business tier to a Java environment using asynchronous connections to message queuing components. It also covered configuring runtime bridges to make the connection and using proxies with both JNBridgePro and Ja.NET.

References

For more information about the details of configuring MSMQ foreign sites
See "Configuring cross-platform messaging"
http://technet.microsoft.com/en-us/library/cc740208(WS.10).aspx

For more information about how to configure and use the MSMQ-MQSeries Bridge
See "Chapter 13 — MSMQ-MQSeries Bridge Configuration Guide"
http://technet.microsoft.com/en-us/library/aa286574.aspx

Start | Previous | Next

Patterns and Practices home

Page view tracker