So far, you have looked at synchronous calls between .NET Framework and Java applications using .NET Remoting and Web services. Synchronous calls require a response from the provider component that returns the results to the consumer, with the requester waiting until it receives the response. With high-speed, permanent link WAN links, this is the preferred approach. Even in the higher latency environment of the Internet, synchronous calls can be more than adequate.
However, what do you do if there is no guarantee that the provider application is available? What if the link to that component is non-permanent, or other factors (such as loading levels and queuing) prevent synchronous operation? In this case, you can implement asynchronous communication.
With asynchronous communication, there is no guarantee that the provider application is available. Hence the consumer application adds its request into a messaging queue, and then it awaits the response when the provider can process it. Another example might be where the provider needs to expend significant processing resources in producing a result, possibly contacting other providers for information before being able to formulate a response.
Asynchronous processing is ideal to use in many situations — especially on the Web, where a user’s request could take a long time to process, but you want to provide a response back to the user immediately. By handling the user’s request asynchronously, your system can respond regardless of how long that request may actually take to execute.
Operations that fall into this category include placing an order at an online store with a credit card or making a request to a fulfillment center. Rather than keep the user waiting while the credit card company authorizes the payment or the fulfillment center puts the order together, the application lets the user know the order was placed successfully. A later e-mail notification could confirm that payment was made or the order assembled.
Asynchronous operations fall into two main types:
Non-blocking operations — This is where the client handles the asynchronous call. The call itself is synchronous, but the client switches the call to another process or thread, allowing other operations to proceed uninterrupted until the response returns.
One-way operations — This is a true asynchronous operation, in that the client makes the request which is handled by a separate server component. The client can then check up on the progress of the request by looking at status information before receiving the result of the transaction.
This next section looks at using Web services to make non-blocking asynchronous calls between .NET Framework and Java applications. The rest of the chapter then moves on to address the true one-way asynchronous operation support available in message queuing products.
Although Web services are synchronous in nature, you can use them to implement non-blocking asynchronous connectivity. Non-blocking asynchronous calls are not truly asynchronous, but they allow a client application to continue to function by spawning a separate process that handles the asynchronous operation. This section looks at the techniques for implementing non-blocking asynchronous connectivity with Web services.
It is important to start out by differentiating the two following scenarios:
Implementing an asynchronous call to a Web service.
Implementing a Web service that is itself asynchronous.
In the first scenario, a client application calls a “slow” Web service asynchronously to allow the application to continue processing while the slow Web service call is in progress. The second scenario is where a Web service operates asynchronously on the Web server to increase its performance. However, this second option still results in a Web service that accepts synchronous connections. This guide discusses only the first scenario.
When you call a Web service from a .NET Framework client application, you can either call the method synchronously or asynchronously. In Chapter 4, “Interoperability Technologies: Point to Point,” you saw how a Web service client uses methods in an auto-generated proxy class to make calls to a Web service. You create this proxy class for your client when you add a Web reference to your client project, or when you use the Web Services Description Language tool (Wsdl.exe), which automatically creates methods for calling the Web service method synchronously or asynchronously. This is true even if there is only a synchronous implementation of the XML Web service method.
For example, if the Web service exposes the method GetProductsByCategory, the proxy file would contain three methods named GetProductsByCategory, BeginGetProductsByCategory, and EndGetProductsByCategory. The first method calls the Web service synchronously as normal. The second two handle the asynchronous call. The Begin method initiates the call to the Web service, while the End method retrieves the results. Calling the Begin method in the proxy class from the client starts a second process that makes the synchronous call to the Web service, allowing the client to continue while the Web service call executes.
The obvious question is how does the client know when to call the End method? There are four main ways of doing this:
Pass a callback function into the Begin method. The second process then calls the callback function when the message has finished processing. This is the preferred method as the callback functions do not block threads while awaiting the response.
Use one of the WaitHandle methods of the IAsyncResult.AsyncWaitHandle object. When using the methods of the WaitHandle class, the client can also specify a timeout after which it abandons waiting for the results.
Poll the value of IAsyncResult.IsCompleted. When this property returns true, the XML Web service response is available.
Call the End method directly. This method does not return until the asynchronous operation is complete since it uses IAsyncResult.AsyncWaitHandle.
Using asynchronous communication improves system usage and avoids the situation where the client has to wait while the Web service delivers the results of an operation. Your decision to call a Web service method synchronously or asynchronously should be based upon performance. However, communication from the client application is still one-way, so this is not a true asynchronous implementation.
For more information about asynchronous calls to Web services, see the References section at the end of this chapter.
Implementing this “pseudo-asynchronous” operation is easy to achieve in .NET Framework Web service client applications. You can also achieve this style of operation in Java Web service clients, depending on the features that your Java Web Services Toolkit provides.
However, a call to a Web service using this asynchronous technique would not survive the client going offline and coming back online later in the week. If the transaction takes more than a few minutes (or even seconds), the user is unlikely to keep the connection open. Hence implement non-blocking asynchronous operation only if the following factors are true:
The client and Web service have permanent connectivity.
The call to the Web service does not take too long to complete.
The client can work on other tasks during the Web service call.
If any of these factors are not true, you should consider moving beyond the non blocking implementation with Web services toward true asynchronous operation using a messaging or queuing infrastructure.
You have seen how you can call Web services to simulate non-blocking asynchronous calls. Now, you will look at how to use message queuing to achieve true asynchronous communication, and then how to connect .NET Framework and Java applications.
Message queuing is a technique where processes or program instances can exchange or pass data through an interface to a system-managed queue of messages. Messages can have different lengths, types, and uses. You can have one process create a message queue with which multiple processes can interact, by reading or writing messages. For example, a client process can write messages to a message queue which a server process can later read or vice versa.
By placing a message representing a task (for example, an order for fulfillment) into a queue rather than processing the task synchronously, the application only has to post the message to the queue. Any number of different applications (potentially on different platforms) can post messages to a queue, and any number can be used to retrieve and process those same messages, providing scalability to your application.
Figure 5.4 shows an overall view of how message queuing works between two applications. Using a messaging API, an application creates a message with a data payload. The message queue system, through the queue manager, takes care of marshaling the data in the proper format to place the message in the queue. The queue manager also takes care of locating the destination queues (there may be more than one), whether they are on the local computer or on a remote computer on the network.
Figure 5.4: Example of a message queuing application
Note | In Figure 5.4, the sender and receiver applications may be on different platforms. |
Several vendors produce message queue products, including:
Microsoft Message Queuing (also known as MSMQ)
IBM WebSphere MQ (formerly known as MQSeries)
Sun ONE Message Queue
BEA Message Q
These message queue products typically are responsible for managing the queues on a system. Applications typically send and receive messages from a queue using an API.
To discuss interoperability between .NET Framework and Java applications, this guide focuses on Microsoft Message Queuing and IBM’s WebSphere MQ. The reason for discussing IBM’s WebSphere MQ is because it is quite popular in enterprise environments, particularly those using Java. The next few sections look at using both Microsoft Message Queuing and WebSphere MQ to enable interoperability between .NET Framework and Java applications.
Microsoft Message Queuing (MSMQ) is a feature of the Windows operating system. MSMQ provides an inter-application messaging infrastructure, implementing the features for sending messages between disconnected applications. This is a crucial requirement for using Business tier components in an application.
MSMQ has been through several releases. MSMQ 1.0 was introduced as a part of the Windows NT 4.0 Options Pack and was also available for Windows 95 and Windows 98. MSMQ 2.0 is part of Windows 2000. The latest version, MSMQ 3.0 now ships with Windows XP Professional and Windows Server 2003. There is also a version of MSMQ for Windows CE.
Note | MSMQ in Windows NT 4.0 Workstation Windows 2000 Professional and Windows XP Professional can access only local private queues. |
Because it is tightly integrated with Windows, MSMQ offers several benefits, such as the ability to utilize COM+ transactions, alignment with the Windows security model, and clustering. MSMQ 3.0 provides some additional features such as the ability to use HTTP as a transport, SOAP Reliable Messaging Protocol (SRMP) support, multicast options, triggers, and a number of management and deployment upgrades.
MSMQ fulfils a number of application requirements:
Message transport — MSMQ handles packaging the message and transporting it across the network to the receiving application. It uses its own IP-based protocol as well as HTTP for transport (version 3.0 only), and COM/DCOM for object serialization when the body includes an object.
Resilient queues — An MSMQ queue is an in-memory or persistent store of messages waiting for delivery. An application can view messages in the queue without removing them, filter them, and retrieve them from the queue.
Patient disconnection — Unless you specify otherwise, a message sits and waits in a queue until an application comes looking for it. This means that MSMQ supports disconnected applications, where computers are not connected to the same physical network. After the computer reconnects, it can receive any waiting messages.
Transactional messages — The optional transaction features of MSMQ guarantee that messages arrive once and only once, that multiple messages appear in a particular order, and if anything goes wrong, the entire set of messages rolls back to its initial state. MSMQ is a standard resource manager, so it can coordinate activity with other resource managers, such as Microsoft SQL Server, therefore allowing reading and writing of messages and data in the same transaction.
Error handling and auditing — A lot can go wrong with any kind of disconnected application, and MSMQ has to provide robust support for error and audit conditions, such as undeliverable messages or auditing and journaling messages.
For more information about MSMQ features, see the Microsoft Message Queuing (MSMQ) Center Web site.
MSMQ is not part of the default installation of Windows Server 2003. To install MSMQ, add it using Add/Remove Windows Components under Add or Remove Programs in Control Panel. Go to the Application Server section and select the Message Queuing check box.
For detailed instructions about how to install MSMQ, see Chapter 9, “Implementing Asynchronous Interoperability.” For more generic information, see “Installation Overview for Message Queuing” in Windows Help.
You can administer MSMQ through the Computer Management console. You can use this tool to create, view, and manage queues. In this tool, you find MSMQ items under the Message Queuing object. There are four containers:
Outgoing Queues — Holds outgoing messages, normally for routing purposes.
Private Queues — Lets you create a private queue to which you can send messages.
Public Queues — Enables you to create a queue that Active Directory publishes.
System Queues — Contains system level queues, such as “dead letter” queues to store messages that MSMQ could not deliver.
For more information about administering and configuring MSMQ, see Windows Help.
MSMQ offers the choice of creating public queues or private queues. The main differences between public and private queues are as follows:
Public queues appear in Active Directory and private ones do not, so you can only access private queues by knowing the queue address.
Private queues do not incur any overhead from the Active Directory.
Public queues are only available in a domain environment. In a workgroup environment, you can use only private queues.
Private queues can operate when the Active Directory directory service is unavailable.
Note | Unless your design is tightly bound to Active Directory authentication, use private queues. |
Now that you understand the basics of MSMQ, this next section shows you how to use it to enable asynchronous interoperability between .NET Framework and Java applications. Chapter 3, “Interoperability Fundamentals,” described how to get .NET Framework and Java applications to agree on a common format for exchanging data. Assuming you have created a common data format, then in theory if you can send and receive messages to and from MSMQ using .NET Framework as well as Java applications, MSMQ can act as an asynchronous link between the two platforms, as Figure 5.5 shows.
Figure 5.5: Message Queuing enabling asynchronous interoperability between .NET Framework and Java applications
Programmatic access to MSMQ from a .NET Framework application is now a relatively easy process, although this was not always the case. Although MSMQ is conceptually quite simple, the original Win32 APIs involved significant low-level programming. The first improvement was the development of a COM interface. However, in the .NET Framework, Microsoft provides a namespace and a set of classes that support MSMQ. The System.Messaging namespace makes programming MSMQ consistent with programming the .NET Framework.
System.Messaging contains the set of classes that wrap the underlying MSMQ infrastructure. From these classes, there are three classes that you find yourself using most often when programming MSMQ:
MessageQueue
Message
MessageEnumerator
The next sections describe each of these classes.
The MessageQueue class is the primary class for interacting with message queues on local or remote computers. You can use it to perform tasks such as enumerating the queues on a particular computer, retrieving messages from a queue, sending messages to a queue, and creating and deleting queues. Almost everything you do with MSMQ in the .NET Framework starts with an instance of the MessageQueue class.
The Message class lets you access and manipulate individual messages in a queue, as well as format and fine-tune a message that you add to a queue. In most cases, you use a Message object to receive a reference to a specific message as you loop through a collection of messages.
The Body property of the Message object stores the message data. Sending the message serializes the contents of the Body property, using the Formatter property you specify. This is similar to the serialization techniques discussed in Chapter 3, “Interoperability Fundamentals.” MSMQ provides both a binary and an XML formatter. You can find the serialized contents in the BodyStream property. You can also set the BodyStream property directly, to perform tasks such as sending a file as the data content of a message. You can change the Body or Formatter properties at any time before sending the message, which serializes the data appropriately when you call the Send method of the MessageQueue object.
The MessageEnumerator class is unique in that it provides very flexible access to the messages in a queue, as a dynamic collection of messages. It is the best means to process multiple messages because it gives you the flexibility to peek at or to receive messages as necessary. A MessageEnumerator object is a cursor with references to messages in the order the messages appear in the queue, ranked according to message priority. You can use a MessageEnumerator to step through the queue and examine or access the messages in the order in which they appear in the queue. However, the MessageEnumerator class provides a forward-only cursor, so you cannot step back through the queue with MessageEnumerator.
Note | An enumerator does not remove the messages from the queue when it queries the queue. It returns information about the message at the current cursor position, but it leaves the message in the queue. |
For more information about the MSMQ-related classes in the System.Messaging namespace and how to program against MSMQ, see the “.NET Framework Class Library” on MSDN.
You have to be able to specify a message queue before you can use it. To do this, you need a way to describe a queue uniquely and consistently in your applications. The .NET Framework provides three different ways to access a specific queue:
Specify a queue by its path — A path to a queue looks like <servername>
\private$\<queuename>, netserver\private$\Orders, which specifies the computer name (or “.” for the local server) and the full path to the queue.
Specify a queue by format name — This option uses Format Name, which is a string that describes the queue through some connection details and the queue’s path, for example, DIRECT=OS:netserver\private$\Orders or using a special GUID that uniquely identifies the message queue.
Specify a queue by label — This method uses the queue’s label (“My Orders”), a value that you can assign through code or through the Message Queuing administration interface.
Using either the label or the path methods adds overhead, because MSMQ must resolve those descriptions into the Format Name that it uses internally to describe individual queues.
Using a Format Name directly avoids the name resolution, making it a more efficient method; it is the only way you can refer to a queue if you want your client application to be able to function when a queue is offline. However, specifying a queue by its path is the only option available when creating a new queue, because the other two reference options rely on properties of the queue that can be set only once the queue exists.
Sending a message to a MSMQ queue is a relatively straight forward process.
To send a message to a MSMQ queue
Open the queue you want to send a message to by creating an instance of a MessageQueue object and specifying the queue name as a parameter to the constructor.
Set the Formatter property of the MessageQueue object to use the type of formatter (binary or XML) you want to be used for serializing the contents of your message on the queue. If you do not specify the Formatter property, the XML formatter will be used.
Create a new Message object and set the value of its Body property to the object you want to send to the queue. For example, an OrderData object containing the details of an order.
Send the message to the queue by calling the Send method on the MessageQueue object with the Message object as a parameter.
For a detailed example of sending a message to a MSMQ queue from a .NET Framework client, see Chapter 9, “Implementing Asynchronous Interoperability.”
The MessageQueue class supports the MSMQ ability either to peek at or to receive messages. Peeking means that you examine the first message in a particular queue without removing it from the queue. This is a handy way to look at the queue and implement logic for handling messages in a different order from the order they appear in the queue. However, Peek allows you to see only the first message in the queue. Because peeking does not remove that message from the queue, you cannot then peek at subsequent messages.
Note | If you want to see all the messages in a queue without removing them from the queue, you can use the GetAllMessages method or the GetMessageEnumerator method. |
After the application peeks at a message in the queue, it can elect to receive the message, or it can directly receive it without peeking. Receiving a message means that the message leaves the queue, and the application can do whatever is appropriate with the message. When an application receives a message, that message leaves the queue permanently, unless some process returns it to the queue.
Retrieving a message from a MSMQ queue is also a straightforward process.
To retrieve a message from a MSMQ queue
Open the queue you want to receive a message from by creating an instance of a MessageQueue object and specifying the queue name as a parameter to the constructor.
Set up the correct formatter using the MessageQueue.Formatter or Message.Formatter properties. The formatting on the sender side must match that on the receiver.
Call the Receive method of the MessageQueue object to return a Message object.
Cast the value of the Body property of the Message object into the type of object you are expecting to receive.
Note | An application can peek or receive messages either synchronously or asynchronously. The MessageQueue class provides PeekCompleted and ReceiveCompleted events you can use to receive events asynchronously. Typically, an application using these events specifies a timeout to limit the duration an application sits waiting for messages. |
For a detailed example of retrieving a message from a MSMQ queue in a .NET Framework application, see Chapter 9, “Implementing Asynchronous Interoperability.”
So far, this guide has described how a .NET Framework application can implement asynchronous connectivity by sending and receiving messages to and from MSMQ. But what can MSMQ do for J2EE services and Java clients?
In general, enabling Java applications to interoperate with MSMQ is not an easy thing to do. Microsoft does not currently provide an MSMQ client for Java. To access MSMQ from a Java application, you need to implement other strategies.
At present, there are three ways of doing this:
Using a Java to COM Bridge.
Using a JMS Provider for MSMQ.
Creating a Web service interface.
The following sections describe each of these techniques.
Although native Java clients cannot talk direct to MSMQ, existing COM clients can talk direct to MSMQ by using the COM API. COM clients include Microsoft Visual Basic and C/C++ applications based on the Win32 platform. Third-party vendors supply products that let you call the COM API from a Java client, in effect linking Java clients to MSMQ through COM as shown in Figure 5.6.
Figure 5.6: Accessing Message Queuing through a Java-to-COM bridge
The benefits of this approach are that the MSMQ COM libraries are quite extensive and provide a rich interface to MSMQ without requiring you to create any additional wrapper or interface. However, one disadvantage in this approach is that the Java client must be Windows-based to use the Java-to-COM bridge, and you must install the COM libraries for MSMQ. This requirement rules out using Java clients running on operating systems other than Windows.
The second issue is that network connectivity needs to use DCOM over a custom TCP socket. DCOM does not work well in Internet-based distributed environments.
Note | Intrinsyc provides a Java-to-COM bridge called J-Integra that does not require you to use a Windows-based Java client or to install the COM libraries for MSMQ. For more information, see the References section at the end of this chapter. |
JMS is the Java Messaging Service API and is part of the J2EE specification. It provides an abstraction layer for several message queuing products, and all J2EE vendors implement JMS support. To access a queue using JMS, you need a JMS provider for that type of queue. Although this would be a good solution for accessing MSMQ from Java, there are currently no JMS providers for MSMQ.
A more involved approach to connecting Java to MSMQ is to use a Web service interface. In this approach, you create a .NET Framework Web service that exposes the functionality of MSMQ. A Java client can then access MSMQ by making calls to the Web service. Figure 5.7 shows this approach.
Figure 5.7: Accessing MSMQ using a Web service interface
For an example of a Web service interface that exposes MSMQ to Java clients, see the section named “Creating a Web Service Interface for MSMQ” in Microsoft .NET and J2EE Interoperability Toolkit by Simon Guest.
The Web service interface provides an interesting approach for linking J2EE to MSMQ. Again, with interest building in Web services, there is a lot of momentum in developing Web service interfaces for a range of components.
However, implementing a Web service interface for MSMQ does not provide all the answers and in some areas could be viewed as a backward step. Certain functionality that MSMQ provides would suffer from this approach, in particular:
Reliable messaging.
Transactional support.
True callback.
There are new and emerging Web services specifications that offer solutions in the first two cases, as this next section illustrates.
The problem with reliable messaging and Web services is that Web services use HTTP as the underlying transport protocol. Although HTTP contains features that enable connection retries, you cannot regard it as a reliable protocol. For example, HTTP does not report back to IIS on successful or unsuccessful message delivery. Hence if you link to MSMQ using Web services, you sacrifice the delivery guarantee that MSMQ provides.
The Web services reliable messaging protocol (WS-ReliableMessaging) is a new specification for providing reliable messaging over Web services. WS ReliableMessaging consists of a protocol that can identify, track, and manage message delivery between two computers. The protocol itself uses SOAP headers and bindings to provide reliability. For more information about WS-Reliable Messaging, see “Web Services Reliable Messaging Protocol (WS-ReliableMessaging)” on MSDN.
The Web services Basic Profile 1.0 specification does not implement support for transactions. Transaction support involves guarantees that a set of operations or transaction, either completes successfully or rolls back to the state before the operations started.
The standard example is one of transferring money from one bank account to another. This process involves reducing the balance on one account and incrementing the balance on the other. If one operation completes and the second operation does not, you can end up with money disappearing out of one account and not appearing in the other. By making these two operations a transaction, you ensure that either both complete or both roll back to the starting position, thus undoing all changes.
Implementing transaction support within a Web service is difficult, but not impossible. The transaction process in the preceding example requires a number of steps:
Create the transaction.
Send message requesting money from account #1.
Send message adding money to account #2.
Commit or abort the transaction.
A Web service is capable of handling only one action at a time. Also, Web service calls are stateless, so there is no affinity between the client and the service. For example, the Web service could send a message to a queue that requests money from the first account, but after it completes that task, it is finished. If the client calls back again, there is no inherent way for the server to know that it is the same client.
One approach to implementing transactional support in Web services is to store session state information in the Web application. In the preceding example, the Web service can hold the client requests for each of the four tasks in session state, and then process them only after it receives the commit request. Figure 5.8 shows an example of this scenario.
Figure 5.8: Handling a transaction using a Web service
Implementing session state in a Web service is not without penalties. Storing session state uses a lot of memory resources. This resource usage can cause limitations on scalability. It can also make you susceptible to denial of service attacks or even simple overload when the Web server runs out of memory due to the creation of multiple state objects.
Web Services Transaction (WS-Transaction) is a new specification that applies transactional support to Web services. It covers both atomic transactions and business activities. Atomic transactions are discrete, self-contained, short-lived transactions, whereas business activities cover transactions that take significant time to execute, and that you cannot simply roll back to the previous state. For more information about WS-Transaction, see “Web Services Transaction (WS-Transaction)” on MSDN.
True callback support in MSMQ enables a messaging server to notify a client of the arrival of a message in a queue or of other events. To do this, you provide the queue with a callback location when connecting to the queue or sending a message. The queue registers the callback location and then sends notifications according to the selected criteria. Alternative approaches use UDP multicasting to notify multiple clients immediately. MSMQ version 3.0 implements the Pragmatic General Multicast (PGM) reliable multicast protocol.
This differs from pseudo-callback support, where the client has to poll the queue to see what is in it. AsyncCallBack is an example of this pseudo-callback function. The System.Messaging namespace supports AsyncCallBack through the BeginReceive and EndReceive methods within the MessageQueue class.
Note | AsyncCallBack is not a true callback function because although the operation spawns a second, non-blocking thread, the mechanism is still of a request-response nature. |
Today’s Web services can offer only pseudo-callback support, again because the current implementations depend on HTTP as the transport protocol. HTTP supports only request-response type interactions; this makes notification very difficult. If Web services become truly protocol independent (as in the Web services definition), it may then be possible to implement a true callback function using Web services.
WebSphere MQ (formerly MQ Series) is IBM’s equivalent of MSMQ and has evolved from IBM’s mainframe days. WebSphere MQ provides assured, once-only delivery of messages. If the receiving application or the communication channel to the receiving application is unavailable, WebSphere MQ automatically stores the message and forwards it at a later time. You can also configure WebSphere MQ to provide acknowledgement messages.
One of the main differences between MSMQ and WebSphere MQ is that WebSphere MQ runs on multiple operating systems, including Linux, UNIX, AIX, HP-UX, Sun Solaris, and Windows. It also supports messaging to more than 35 different platforms. You enable applications to use message queuing using a programming interface known as the MQI (Message Queue Interface). This is a cross platform API, so application calls on one platform easily port to another. WebSphere MQ provides both a Java and .NET Framework implementation of the MQI functionality, together with J2EE JMS Support.
In WebSphere MQ, queue managers manage the queues. Queue managers provide the messaging services for applications and process the Message Queue Interface (MQI) calls from applications. The queue manager handles the placing of a message in a queue or the routing of a message to another queue manager.
Note | Before you can do anything with WebSphere MQ, both the queue manager and queue must have been created and be accessible to the computer running the application. |
For an application to send or receive a message, it must first connect to the queue manager. The queue manager provides a connection handle; the application uses the connection handle for MQI calls during that session.
After the queue manager creates this connection handle, the next task is to open a queue. You can open a queue for getting (reading) or putting (writing) a message. The queue manager is responsible for opening the queue, and returns an object handle if successful. Your application uses the object handle and the connection handle whenever it gets or puts messages on the queue.
When sending a message, you must open the queue for putting. Sending a message involves packaging the data you want to send into a data buffer and providing other information such as destination and message type. To receive a message, the queue must be open for getting.
Note | The maximum message size that WebSphere MQ supports is 4 MB, although not all operating systems support this range. For example, Windows and DOS applications have a 32 KB message size. |
WebSphere MQ for Windows provides a Microsoft Management Console (MMC) snap-in for managing queue managers and queue definitions. When you install WebSphere MQ, this creates the default queue manager, which you can then configure. You can add different queue managers, and even change the default using the MMC tools.
Part of the function of the queue manager is to provide access to the queues. You can use the MMC snap-in to create four types of queues:
Local Queue — A queue that belongs to the local queue manager.
Alias Queue — A queue definition that uses another queue for its implementation, letting clients connect to the alias name but transferring the queue requests to another local queue.
Model Queue — Allows you to define a model or template that an application can use to create queues dynamically.
Remote Queue Definition — Lets you to provide a hook into queues configured on different computers.
Note | You can only send messages to remote queues, not receive them. |
For more information about administering WebSphere MQ, see the IBM WebSphere MQ Web page.
WebSphere MQ has a client component that you can install on a separate computer. The client enables applications to communicate with queue managers residing on a different computer, which could even run on a different platform.
In Chapter 2, “Understanding Enterprise Platforms,” you saw that Java Messaging Service (JMS) is an API that provides application abstraction when accessing message queues. You also saw that JMS is not a product but a service definition. The JMS specification and API is part of J2EE, but it is up to third-party vendors to implement the standard. For more information about the JMS standard, see “Java Message Service API” on the Java Web site.
Several message queue vendors with a Java background have implemented JMS providers for their products. This provider acts as a binder between the message product and the JMS API. Ideally, this should enable portability by allowing you to switch operating system vendors without affecting the operation of the JMS component.
With JMS, you can implement two types of messaging support or messaging domains:
Queue-based or point to point.
Publish/Subscribe.
Queue-based messaging is similar to that in MSMQ. Both the sender and receiver agree on a pre-defined queue, using the JMS type javax.jms.Queue to handle asynchronous messages. A client can send a message to MyPrivateQueue, and the receiver receives the message back from the same queue. The receiver then acknowledges successful processing of the message.
Note | With point-to-point messaging, each message has only one consumer. |
JMS also supports the Publish/Subscribe model by categorizing queues into topics using the javax.jms.Topic class. Publishing applications publish new messages to the topic (or queue) and any subscribers then receive the published message. You can create one-to-many, many-to-one, and many-to-many relationships between subscribers and topics.
The JMS specification enables you to control how durable topic messages are and therefore how long they remain in the topic queue after publication. Figure 5.9 shows an example of the Publish/Subscribe model. A feed provides a continuous flow of information, which the queue manager pushes out to subscribers. Applications, such as a stock trading program, can consume this information and traders then use it as a basis for buying and selling stock.
Figure 5.9: Publish/Subscribe domain in the JMS specification
Note | A major difference between point-to-point and Publish/Subscribe is in timing. Point-to-point messaging works even if the client is offline. With Publish/Subscribe, clients need to be active to consume messages. Durable subscriptions provide a workaround to this, receiving messages while subscribers are offline. |
Topic management can be an interesting challenge because clients can create and modify topics dynamically, meaning that fixed queues cannot be guaranteed. However, message vendors generally implement mechanisms for the management of topics. For example, the SupportPac MA0C for WebSphere MQ uses predefined system queues and channels.
JMS supports five message types:
javax.jms.TextMessage — For simple string messages.
javax.jms.BytesMessage — For sending raw bytes as messages.
javax.jms.ObjectMessage — Sends a serializable Java object as a message.
javax.jms.MapMessage — Sends a message that supports name/value pairs similar to a hash table.
javax.jms.StreamMessage — Supports the same types as MapMessage, but where the contents of the message must be in order.
Note | These message types all implement the javax.jms.Message interface. |
There are three ways to connect to WebSphere MQ from a J2EE application:
Using the WebSphere MQ Classes for Java.
Using the WebSphere MQ Classes for JMS to Achieve Point-to-Point Messaging.
Using the WebSphere MQ Classes for JMS to Achieve Publish/Subscribe Messaging.
The following sections discuss each technique.
The proprietary WebSphere MQ classes for Java allow you to connect to WebSphere MQ server, either directly or through the WebSphere MQ client. These classes allow Java applications, applets, and servlets to communicate with WebSphere MQ. The WebSphere MQ classes for Java are part of a package named com.ibm.mq. You must import this package to use classes in your Java code.
Sending and receiving messages using the WebSphere MQ classes for Java is a trivial task. You create a connection to a queue manager, open the queue, create a message, and then put it in the queue. The following code demonstrates this with a simple “Hello World” message.
// Create a connection to the QueueManager MQQueueManager queueManager = new MQQueueManager("QM_MYQM"); // Open the desired queue MQQueue queue = queueManager.accessQueue("myQ", MQC.MQOO_OUTPUT, "QM_MYQM", "myQ", ""); // Create a new message MQMessage myMessage = new MQMessage(); // Specify the message format myMessage.format = MQC.MQFMT_STRING; // Populate the message data buffer with the "Hello World" string myMessage.writeString("Hello World"); // Create the default message options MQPutMessageOptions pmo = new MQPutMessageOptions(); // Put the message into the queue queue.put(myMessage,pmo);
In addition to placing primitive data types or strings, you can also write Java objects out to the queue. This uses the standard Java serialization mechanism to write the contents of your object into the message buffer.
Note | While this is great for Java-to-Java applications, other platforms, including .NET Framework, do not understand the format of the serialized message. |
If you want to use the WebSphere MQ classes for Java for interoperability, you have several challenges ahead. First, you must be aware the MQ classes for Java are not part of the J2EE specification, and therefore only WebSphere MQ implements these classes. If you are using a different message queuing product, you cannot use the com.ibm.mq package.
If you are happy using WebSphere MQ, your next problem is how to handle complex data. The differences between the serializers in the .NET Framework and Java means that you cannot put objects in a queue from one platform and take them out from the other. Hence interoperability at the object level is not possible.
However, you can serialize your data as an XML string, as discussed in the section about Web services in Chapter 4, “Interoperability Technologies: Point to Point.” Java, the .NET Framework, and WebSphere MQ can all handle strings, so you can package up a customer object as an XML formatted string and then place it in the queue.
The WebSphere MQ classes for JMS implement Sun’s Java Message Service (JMS) interfaces, allowing Java programs to access WebSphere MQ. The WebSphere MQ classes for JMS support both the point-to-point and Publish/Subscribe models of JMS.
This section describes the point-to-point JMS messaging model. The next section describes the Publish/Subscribe JMS messaging model.
There are several key differences if you use the JMS classes to address WebSphere MQ. The most important is that you do not create a connection directly, but create a connection factory. These factory objects then exist within the JNDI namespace, protecting the application from vendor specific details. To obtain the connection factory, you need to retrieve the object from the JNDI namespace.
Note | If you do not have a JNDI namespace available, it is possible to create the factory at runtime. |
After you have the connection factory, use the factory to create a connection that you then start. The following code shows how to obtain the connection factory and create the connection.
InitialContext ic = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ic.lookup(connectionName); QueueConnection connection = factory.createQueueConnection(); connection.start();
After you create the connection, the next task is to create a session. The session provides the context for creating and consuming messages as well as the methods to create the MessageProducer object (used to send messages) and the MessageConsumer object (used to receive messages). You can create a simple, non transactional, automatic acknowledgement session using the following code.
QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
After the application obtains a session, it can create a queue and send a message using a MessageProducer. The definition for the queue can be stored in a JNDI namespace or created at run time. It is best practice to use JNDI to define the queues. An application can obtain a queue using the following code.
Queue queue = (Queue) ic.lookup(queueName);
Using the queue as a parameter, you can create a MessageProducer using the QueueSession. In the point-to-point messaging model, the MessageProducer will be a QueueSender as the following code shows.
QueueSender sender = session.createSender(queue);
Finally, you need to create a message of the correct type. Methods on the QueueSession object allow you to create any of the five types of JMS messages. You can then populate this message with the data you want to send as the following code shows.
ObjectMessage message = session.createObjectMessage(myObject); sender.send(message);
You can use the QueueReceiver to receive a message using the MessageConsumer. You can create this from the session in the same manner as the QueueSender. You can then make a blocking or non-blocking call to receive a message from the queue. The following code shows how to receive a message from the queue. The code blocks until either a message arrives or the timeout expires.
QueueReceiver receiver = session.createReceiver(queue); Message message = receiver.receive(1000);
The message type received is of one of the five types of supported JMS messages. To extract the correct message payload, you must cast the returned message into the correct message type.
Note | It is also possible to receive messages asynchronously. |
JMS messages on WebSphere MQ have a different structure to that of standard WebSphere MQ messages, and the JMS messages need mapping to the WebSphere MQ format. However, this mapping is not important if you send a message through JMS and the receiving application is non-JMS, because you can then configure the queue’s target client as MQ.
The preceding section described how to use the WebSphere MQ classes for JMS to achieve publish/subscribe messaging. This section describes how to achieve Publish/Subscribe messaging.
When you work with Publish/Subscribe messaging, you must decide early on which broker you want to use and configure it to run the WebSphere MQ classes for JMS. The broker has a record of all the subscribers registered for a topic. When an application publishes a message to a topic, the broker forwards the message to the subscribers.
Note | You add Publish/Subscribe support to WebSphere MQ through a SupportPac. For information about how to do this, see the References section at the end of this chapter. |
WebSphere MQ offers three types of brokers:
MQSeries Publish/Subscribe
WebSphere MQ Integrator Broker
WebSphere MQ Event Broker
Broker setup depends not only upon which broker you choose but on how you want to use it. Each broker has its own documentation for configuration and setup.
After the broker is sorted out, you must create JMS objects similar to those used in point-to-point messaging. Specifically, you need to obtain or create the following objects:
TopicConnectionFactory
TopicConnection
TopicSession
Topic
Either a TopicPublisher or TopicSubscriber
The steps are similar to those for the point-to-point technique, as the following code sample shows.
// Create a connection InitialContext context = new InitialContext(); TopicConnectionFactory factory = (TopicConnectionFactory) context.lookup(tcfName); TopicConnection connection = factory.createTopicConnection(); connection.start(); // Create a session TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); // Create a topic Topic topic = (Topic) context.lookup(topicName); // Create a publisher... TopicPublisher publisher = session.createPublisher(topic); // ...or create a subscriber TopicSubscriber subscriber = session.createSubscriber(topic);
Finally, you either publish messages or receive messages in the same way as in the earlier section on point-to-point messaging.
There are two ways to connect to WebSphere MQ from .NET Framework applications:
Using the WebSphere MQ Classes for Microsoft .NET
Using JMS and Third-Party Bridging Products
The following sections discuss each technique and describe the advantages and disadvantages of each.
The WebSphere MQ classes for Microsoft .NET provide access to WebSphere MQ in much the same way as the WebSphere MQ classes for Java. However, although they both use the same object model, the .NET Framework version does not support connection pools or sending messages to multiple queues or topics. Figure 5.10 shows how a .NET Framework client can connect to WebSphere MQ using the WebSphere MQ classes for .NET.
Figure 5.10: A .NET Framework client using the WebSphere MQ Classes for .NET to connect to WebSphere MQ
You can obtain the .NET Framework classes from IBM as part of MQ v5.3 CSD05, which stands for Corrective Service Distribution #5 (equivalent of a service pack). This fixpack installs the Amqmdnet.dll library in the WebSphere/bin directory. The DLL provides a set of classes that you can use with any .NET Framework application.
Note | CSD05 is supported by IBM. You can obtain CSD05 from the IBM Web site. |
Although Amqmdnet.dll exposes managed classes, you should be aware that these classes make PInvoke calls to other MQ client libraries. Hence if your application makes calls to classes in Amqmdnet.dll, you need to install the WebSphere MQ client on the computer on which the application runs if you have not done so already.
Note | PInvoke enables managed code to call methods and functions on a Win32 DLL file. This avoids using COM for interoperability, but the .NET Framework cannot provide managed code functionality such as garbage collection for these calls. |
Amqmdnet.dll exposes classes that are remarkably similar to those in the Java environment, helping developers to port code between the two systems. Data transfer between the Java and .NET Framework clients uses a raw format without any packaging or serialization.
You can send and receive messages from the queue using the same object and method calls as the Java classes, as demonstrated in the following code sample.
// Create a connection to the QueueManger MQQueueManager queueManager = new MQQueueManager("QM_pagdal"); // Open the desired queue MQQueue queue = queueManager.AccessQueue("XBikesQ",MQC.MQOO_OUTPUT, "QM_pagdal", "XBikesQ", ""); // Create a new message MQMessage myMessage = new MQMessage(); // Specify the message format myMessage.Format = MQC.MQFMT_STRING; // Populate the message data buffer with the "Hello World" string myMessage.WriteString("Hello World"); // Create the default message options MQPutMessageOptions pmo = new MQPutMessageOptions(); // Put the message into the queue queue.Put(myMessage,pmo);
Note | Apart from the capitalization of the methods (lowercase in Java, uppercase in .NET), this code sample is identical to the Java version. This is a design goal of the MQI API. |
You can use third-party bridging products such as Ja.NET or JNBridgePro to access the WebSphere MQ JMS functionality from .NET Framework applications. You can do this exactly like accessing JMS functionality from a Java client, with your .NET client making calls directly to the JMS API. To do this, create .NET proxies of all the Java classes that you require to send a message using JMS and invoke them from .NET. The proxies manage the communication between the .NET client and WebSphere MQ. Accessing JMS functionality through bridging has the advantage of allowing you to use familiar JMS APIs to implement messaging from .NET. At the same time, it makes the JMS API look like a regular .NET Framework API.
Figure 5.11 shows how a runtime bridge can allow a .NET Framework client to connect to WebSphere MQ using JMS.
Figure 5.11: Using a runtime bridge to access WebSphere MQ JMS functionality from .NET Framework clients
Chapter 9, “Implementing Asynchronous Interoperability,” shows a detailed example of how to access JMS functionality in WebSphere MQ from a .NET client using both JNBridge and JaNET.
You have seen how .NET Framework clients can consume messages from WebSphere MQ with the WebSphere MQ classes for Microsoft .NET or using JMS through a third-party bridge product. However, there are some issues of which you need to be aware when consuming messages in a .NET Framework client that are placed on a WebSphere MQ queue using JMS.
The main issue with accessing JMS messages from WebSphere MQ is that JMS messages have extra headers that non-JMS applications do not understand. For example, the WebSphere MQ classes for .NET cannot un-package a JMS formatted message. However, if you use a third-party bridging product to connect to WebSphere MQ through JMS, this is not an issue as the bridging product handles and translates the JMS message headers.
To enable a .NET Framework client to consume JMS messages from WebSphere MQ using the WebSphere MQ classes for .NET, ensure that the Java application sending the messages sets the target client in JMS to MQ. This allows the Java application to send JMS messages without the troublesome headers. While the WebSphere MQ classes for .NET cannot un-package a JMS formatted message, they have no trouble un-packaging an MQ message.
Note | .NET Framework clients cannot reconstruct objects serialized from Java so any messages must be sent as basic data types. |
A major interoperability issue with the JMS Publish/Subscribe model is that it is impossible to link in to the model with a .NET Framework client using the WebSphere MQ classes for .NET. The only way to access the Publish/Subscribe model from .NET is to use a bridging product that wraps the JMS calls. This is because clients create topics in a dynamic fashion.
WebSphere MQ does not implement a one-to-one relationship between queues and topics, because this restricts the number of allowed topics. The WebSphere MQ Classes for .NET do not support accessing topics. Also, because WebSphere MQ handles topic queues as system objects, .NET Framework clients cannot access the queues. Even the MQQueueManager class does not enable you to associate a queue with a topic. Hence only JMS clients can access JMS topics or act as publishers or subscribers. This makes interoperability using direct communication from .NET Framework clients using the WebSphere MQ classes for .NET very difficult to achieve.
Note | You can achieve this interoperability using a bridging product, such as JNBridgePro or Ja.NET. |
In the next section, you go on to see how you can use the bridging functionality within Host Integration Server to link .NET and Java applications.