Using MSMQ


MSMQ allows applications that might run at different times to communicate with each other via one or more centrally located queues. Applications use these queues to send and receive messages. These messages can contain most types of data (such as simple primitive data types and complex data types).

MSMQ 1.0 was introduced as part of the option pack with Microsoft Windows NT 4.0. The release of version 2.0 coincided with the release of Microsoft Windows 2000, and as a result, developers were able to take advantage of more integrated features. This included the ability to leverage COM+ transactions, alignment with the Windows security model, and clustering.

The latest version, MSMQ 3.0, is now shipped with Microsoft Windows XP Professional and Microsoft Windows Server 2003. It boasts all the features of 2.0 and includes HTTP as an optional transport, SOAP Reliable Messaging Protocol (SRMP) support, multicast options, triggers, and a number of management and deployment upgrades. Additional details on MSMQ can be found at http:// www.microsoft.com/windows2000/technologies/communications/msmq/default.asp .

For the samples in this chapter, we'll look at this latest version of MSMQ, shipped with Windows Server 2003, and investigate the options for connecting to queues by using both .NET and Java clients . The samples will also work for users who are working with Windows XP Professional. This is the first technical option we'll examine in the book to provide asynchronous interoperability between the Java and .NET platforms.

Installing MSMQ on Windows Server 2003

Installation of MSMQ on Windows Server 2003 follows a similar pattern to installing UDDI Services ”MSMQ is installed via the Add/Remove Windows Components portion of Add Or Remove Programs in the Control Panel. The required components can be found in the Application Server section, under a category named Message Queuing, as shown in Figure 8.4.

click to expand
Figure 8.4: Installing MSMQ on Windows Server 2003.

Within this category, you have a number of additional options, as shown in Figure 8.5.

click to expand
Figure 8.5: Options for installing MSMQ on Windows Server 2003.

Feel free to select any of these options (in addition to the required Common option) if you plan to experiment further with the MSMQ product set. Completing the Add/Remove Windows Components wizard will install MSMQ on the machine.

Administration of MSMQ is performed by using the Computer Management console, found in Start/Program Files/Administrative Tools. This is shown in Figure 8.6. When using Windows Server 2003, another route for accessing the same tree is through the Application Server administration console.

click to expand
Figure 8.6: Administering MSMQ through the Computer Management interface.

This tool is used to configure systemwide settings, such as events, services, and storage. The Services And Applications tree contains an option for Message Queuing, as shown in Figure 8.6. This option contains a number of subfolders :

  • Outgoing Queues Used for outgoing messages, normally for routing purposes.

  • Private Queues You can create, manage, and programmatically send messages to the queues contained in this folder. We'll use these queues throughout the samples in this section.

  • Public Queues Used for creating, managing, and programmatically sending messages to queues that will be made public to other users and computers. This option will be available if the server resides within an instance of Microsoft Active Directory directory service.

  • System Queues Contains system-level queues ”for examples, dead-letter queues, which store messages that couldn't reach their destination.

  • Message Queuing Triggers Used to configure triggers and rules that can specify actions that occur when messages of a certain type are sent to a queue. This option will be available if MSMQ Triggers was selected at install time.

For these samples, we'll use a number of private queues. Right-click the Private Queues folder and select New. Create a queue named stockpurchases , as shown in Figure 8.7. (Casing doesn't matter for queue names .) This queue will be used to accept messages for incoming stock purchases from the fictitious set of examples that we've been working with. The queue shouldn't be labeled as transactional at this stage.

click to expand
Figure 8.7: Creating a new, nontransactional queue in MSMQ.

Click OK to create the queue, which will now appear in the Private Queues folder. Using the same process, create a second queue, named stocksales . Again, this queue shouldn't be labeled as transactional. When complete, you should have two entries in the Private Queues folder, as shown in Figure 8.8.

click to expand
Figure 8.8: Viewing the queues in the MSMQ administration interface.

Now that you've installed the MSMQ components for Windows Server 2003 and created two queues to represent incoming stock purchases and sales from potential clients, let's look at how to access the queues programmatically.

Simple Message Queue Operations in .NET

Accessing MSMQ in .NET is performed by using the System.Messaging namespace. This namespace allows individual queues to be accessed, messages to be composed and retrieved, and a number of other message queue “ related functions.

To show how classes and methods within this namespace can be used to access the two queues configured in the last section, refer to the sample code found in the C:\Interoperability\Samples\Resource\MSMQ\Simple directory. The main class (Client.cs) shows a series of calls used to place a message on each of the queues, a pause to allow the queues to be examined, and then a retrieval of each of the messages from the queues.

The sample code works by first opening the message queues that were previously set up. Two queues, purchasesMQ and salesMQ , are referenced:

 MessageQueue purchasesMQ      = new MessageQueue(@".\private$\stockpurchases"); MessageQueue salesMQ      = new MessageQueue(@".\private$\stocksales"); 

After these queues are opened, the formatter for each of the queues is set. MSMQ has two ways of formatting messages placed in the queue, either by using an XML or Binary formatter. This is similar to the serialization techniques that you saw earlier in the book.

 purchasesMQ.Formatter      = new XmlMessageFormatter(new System.Type[]{typeof(String)}); salesMQ.Formatter      = new XmlMessageFormatter(new System.Type[]{typeof(String)}); 

Here, we use the XmlMessageFormatter to specify that messages placed in the queue will be serialized with the XML formatter. Because messages of type String will be used, you specify this type as a parameter for the formatter.

Next , two messages (one for each queue) are created. These messages are of type System.Messaging.Message . After their creation, the Send method places the messages in the queue:

 Message purchase      = new Message("This could be a message to purchase stocks!"); purchase.Label = "StockPurchase"; Message sale      = new Message("This could be a message to sell some stocks!"); sale.Label = "StockSale";             purchasesMQ.Send(purchase); salesMQ.Send(sale); 

After this is complete, the sample displays a message and prompts for a key to be pressed:

 Console.WriteLine("Messages have been sent.  Check queues, "     +"and hit enter to retrieve..."); Console.In.Read(); 

Build the sample code using the provided NAnt script. Type client at the command prompt to run the client. When prompted to check the queues, reopen the Computer Management console and navigate to the two private queues that were created earlier.

At this point, expand the two queues and open the Queue Messages folder, as shown in Figure 8.9. Observe how the messages currently in the queue are displayed. Double-clicking the messages in this administration tool displays further details about each message.

click to expand
Figure 8.9: A new stock purchase shown in the MSMQ queue.

Navigating to the Body tab in the properties window shows the contents of the message, as serialized by the XML formatter that we configured earlier. (For those security-aware developers in the group , MSMQ does support levels of encryption to prevent this, if desired.) Figure 8.10 depicts the contents of this message.

click to expand
Figure 8.10: The body of the stock purchase message.

Now that you've observed how messages are placed in the queue, return to the running sample application and press Enter in order to continue the process.

To complete the sample, the Receive method from the MessageQueue class is used to read the message from the queue. Once read, the body element of the message is displayed:

 Message incomingPurchase = purchasesMQ.Receive(); Console.WriteLine("Purchase Message received: "     +(String)incomingPurchase.Body); Message incomingSale = salesMQ.Receive(); Console.WriteLine("Sale Message received: "     +(String)incomingSale.Body); 

MSMQ supports two modes of reading messages from the queue. The Receive method returns the first message from the queue and removes that message from the queue. In the event that the message needs to be read but not removed from the queue (for example, to determine whether the message is meant for a particular process), the Peek method can be used. Peek returns a System.Messaging.Message object but leaves the message in the queue.

Java Interoperability Options with MSMQ

So far, you've seen how MSMQ can be called by using a .NET client in order to send and retrieve messages from a queue. In terms of interoperability, what options are available for applications and services that are written using the Java platform?

Microsoft does not publish an MSMQ client for Java. You need to explore other strategies to allow Java clients to send and receive messages from MSMQ.

Based on the experience of customers who've dealt with this situation, enabling Java to interoperate with MSMQ is generally a tough area and one that hasn't been addressed very well by Microsoft or any third-party vendor. With this in mind, let's look at the options that do exist.

Using a JMS Provider for MSMQ

JMS, the Java Message Service API, forms part of the J2EE specification. It is an API that's designed to provide an abstraction layer for a number of message queuing products and is something that we'll look at more closely in Chapter 9, "Asynchronous Interoperability, Part 2: WebSphere MQ."

Although JMS might one day be a suitable solution to access MSMQ from Java (as outlined in Figure 8.11), at the time of this writing no JMS providers exist for MSMQ. A third-party company named SpiritSoft ( http://www.spiritsoft.com ) has been looking at developing a JMS driver to complement their messaging product set.

click to expand
Figure 8.11: How a JMS provider for MSMQ would be used.

Looking back at some of the projects that I've been involved with, I have an idea why no JMS driver for MSMQ exists today. Although JMS is the messaging API for Java, it doesn't offer or dictate any underlying messaging product. Therefore, an organization that wants to use JMS in its applications has to couple this choice with the selection of a message queue provider. As a result, most ”if not all ”organizations that write against the JMS API already have a message queue within the enterprise. Because a message queue is already in place, there's little to no need to replace it with another (such as MSMQ).

Personally, I'd welcome a JMS provider for MSMQ. A number of customers that I've spoken to agree, especially the ones undertaking projects that require this interoperability between MSMQ and J2EE.

Using SRMP on HTTP

Version 3.0 of MSMQ, shipped with both Windows XP and Windows Server 2003, contains support for SOAP Reliable Messaging Protocol (SRMP). When released, SRMP was a Microsoft standard to extend SOAP with a number of headers, allowing a number of quality of service (QoS) attributes.

SRMP runs on top of HTTP and allows messages sent in the format to be based on concepts such as lifetime (the expiration of a message), durability, and delivery and commitment receipts.

Although SRMP was introduced in MSMQ 3.0, no implementations in Java have been reported . If one were to be created or to exist, the topology of a Java client calling MSMQ via this method would look similar to Figure 8.12.

click to expand
Figure 8.12: How a potential HTTP SRMP client for MSMQ would be used.

Given that this looks like a good way to allow Java clients to access MSMQ by using both HTTP and a reliable SOAP mechanism, you might be wondering why SRMP on HTTP hasn't been more widely adopted. I believe this is due to the standard being overtaken by a number of initiatives that are more closely aligned with Web services. We'll take a look at one of these initiatives, Web Services Reliable Messaging Protocol (WS-ReliableMessaging), toward the end of this chapter.

SRMP on HTTP is certainly supported in MSMQ 3.0, and a number of samples are available on the Microsoft Developer Network (MSDN) to show how this can be used from COM-based applications.

Using a Java-to-COM Bridge

As you've seen, the first two options for Java interoperability with MSMQ are technically possible but do not yet have any implementations. This third option is the first that has been implemented.

Although Microsoft does not support a native Java client from MSMQ, support is available for existing COM-based clients. These can include C/C++ and Microsoft Visual Basic applications based on the Win32 platform. A COM API is available to allow these types of clients to call MSMQ.

In addition, a number of third-party companies have released bridges that allow Java clients to call COM-based APIs. Put the two together, and it's possible for a Java client to call MSMQ by using COM, as shown in Figure 8.13.

click to expand
Figure 8.13: How a Java-to-COM bridge can be used to access MSMQ from a Java client.

One company that makes a Java-to-COM bridge is Intrinsyc. We used their Java-to-.NET product, Ja.NET, in Chapter 4, "Connectivity with .NET Remoting." Intrinsyc's Java-to-COM bridge is called J- Integra , which is available from the company's Web site ( http://www.intrinsyc.com ). In addition, Intrinsyc has a white paper showing how the J-Integra product can be used to make MSMQ calls from Java. This can be found at http://www.intrinsyc.com/support/j-integra/doc/servlet_com/ServletToMsmqExample.html .

Benefits and shortfalls of this approach

Using a Java-to-COM bridge can provide a good way to call MSMQ libraries from Java. Although this uses a bridging concept, the MSMQ COM libraries are quite extensive and will provide a rich interface to MSMQ without the need to create an additional wrapper or interface.

A disadvantage of using this approach is that the Java client must be based on the Windows operating system (to use the Java-to-COM bridge), and the COM libraries for MSMQ must also be installed. This is in addition to any bridging software installed on the client, and therefore, this technique cannot be used for Java clients based on other operating systems (for example, UNIX and Linux).

In addition, if this technique will be used over a network, the transport used will be Distributed Component Object Model (DCOM), over a custom TCP socket. As we discussed in our coverage of Web services in Chapter 5, DCOM isn't well-suited for publishing and accessing services over the Internet.

In addition to the COM bridge, an alternative was available in the days of Microsoft Visual J++: using JActiveX to wrap Microsoft ActiveX MSMQ libraries. This approach shares a similar set of benefits and shortfalls to the COM approach.

Creating a Web Service Interface

The final option for accessing MSMQ from Java is the one that we'll expand on during the remainder of the chapter. In the example code, we'll create and use an interface for MSMQ based on Web services, as shown in Figure 8.14.

click to expand
Figure 8.14: Accessing MSMQ using a custom Web service API.

Taking this approach offers some interesting concepts, which we'll discuss in this chapter, as well as a foundation based on some of the interoperability principles that you saw in earlier chapters.

Creating a Web Service Interface for MSMQ

The Web service interface that we'll use can be found in the C:\Interoperability\Samples\Resource\MSMQ\WebServiceAPI directory. Its subdirectories include the Web service itself (SimpleWebService) plus a number of clients, found under the SimpleClients subdirectory.

Open the Service1.asmx.cs file from the SimpleWebService directory. This class contains the main methods for the Web service API that exposes the MSMQ methods. The service class exposes a number of methods as Web services via the WebMethod attribute:

 public void Send(String queuePath, MSMQInterop.Message message) public bool IsQueueEmpty(String queuePath) public bool IsMessageWaiting(String queuePath,     String label, long timeout) public MSMQInterop.Message Peek(String queuePath, long timeout) public MSMQInterop.Message Receive(String queuePath, long timeout) 

The Send , Peek , and Receive methods should look familiar from the overview of MSMQ in the previous section. IsQueueEmpty and IsMessageWaiting are helper methods. They use the Peek method to help simplify a couple of operations.

Looking at the method signatures in this code, you'll notice that when a message is either passed to or returned from the Web service, a type named MSMQInterop.Message is used. Given the Microsoft .NET Framework support for MSMQ, you might wonder why we didn't just expose the default System.Messaging.Message class instead.

Because System.Messaging.Message implements the System.ComponentModel.Component.Site interface, it can't be serialized via a Web service. This is a classic example of a non “XSD compliant data type that can't be passed over a Web service and something that we covered extensively in Chapter 3, "Exchanging Data Between .NET and Java." If we had exposed these types via the Web service, an error similar to the one shown in Figure 8.15 would have occurred.

click to expand
Figure 8.15: Error when trying to expose a System.Messaging.Message through Web services.

To overcome this, a new type named MSMQInterop.Message has been defined. The XML Schema Definition (XSD) document is provided in the Message.xsd file, which was created by hand by using the techniques described in Chapter 3. All classes that use this message type have been generated from this XSD file.

In addition, the Web service code contains two private methods:

 private MSMQInterop.Message     convertToInteropMessage(System.Messaging.Message message) 

and

 private System.Messaging.Message     convertToMSMQMessage(MSMQInterop.Message message) 

These methods are used to convert between the two types (the XSD type and the native System.Messaging.Message type). This allows the Web service interface to expose types of MSMQInterop.Message and convert them to System.Messaging.Message when placing them in the queue. The opposite is true when messages are retrieved from the queue.

Notice that in these methods, you're mapping only two of the elements (body and label) within the message itself. In a production-type system, you'd probably need to offer a richer set of attributes to handle messages of different types.

Configuring and Setting Security for the Web Service Interface

To run the sample client code and show the Web service interface in action, build the code in the SimpleWebService directory by using the provided NAnt script. Once complete, you need to create a new Internet Information Services (IIS) virtual directory to host the Web service. To do this, launch IIS from Start\Programs\Administrative tools. Navigate through the tree, and right-click Default Web Site. From here, select New/Virtual Directory. Ensure that the alias of the virtual directory is MSMQInterop and that the directory points to the C:\Interoperability\Samples\Resource\MSMQ\WebServiceAPI\SimpleWebService directory. For additional information on this process, revisit Chapter 5, where we first created a virtual directory for a Web service.

In addition to creating the virtual directory, you need to correctly set the security for the Web service interface. Access to queues in MSMQ follows the Windows security model, and as a result, any new queues that are created have permissions that are assigned to the creator by default.

To achieve this, you need to ensure that the Web service interface is running under the context of the same user (in other words, the logged-on user ). To do this, you need to configure a couple of settings on the Web service.

The first setting is to ensure that the Web service deals with incoming security credentials and disables anonymous access. In order to do this, you need to configure the security on the virtual directory. This was covered in some detail in Chapter 6.

Within IIS, open the Properties window for the MSMQInterop virtual directory, navigate to the Directory Security tab and edit the authentication and access controls. Within this dialog box, ensure that Anonymous Access is disabled and both Integrated Windows Authentication (for the .NET client) and Basic Authentication (for the Java client) are enabled, as shown in Figure 8.16.

click to expand
Figure 8.16: Configuring the MSMQInterop virtual directory for authentication.

Save these settings to apply the first security change to the Web service.

The second security setting involves setting an impersonation level for the Web service. Although the previous setting configured the Web service to use secure credentials, you need to ensure that any operation performed by the Web service (for example, adding messages to an MSMQ queue) is done under the context of the calling user.

To do this, you create an impersonate setting in the web.config file. This has already been done in the web.config file that's included in the samples. Open this file, and locate the following entry:

 <identity impersonate="true"/> 

This setting allows the Web service to correctly impersonate the calling user.

With this configured, the Web service interface for MSMQ is ready to be tested by your clients. Browsing to http://localhost/MSMQInterop/Service1.asmx will display the Web service access page, as shown in Figure 8.17.

click to expand
Figure 8.17: The deployed MSMQInterop Web service.

These are the Web service methods that we'll consume by clients in both .NET and Java.

Client Access to the MSMQ Web Service Interface

To show how this MSMQ Web service interface can be utilized from either a .NET or Java client, let's look at the sample code that accesses each, located in the C:\Interoperability\Samples\Resource\MSMQ\WebServiceAPI\SimpleClients directory. This directory contains two subdirectories for each type of client.

Each of the samples shown selects a queue to send messages to and receive messages from. The .NET sample code sends a message on the stock purchase queue and receives any incoming messages from the stock sales queue. The Java client does the opposite, sending a message to the stock sales queue and receiving all incoming messages from the stock purchase queue. Both use the Web service interface to access MSMQ. Figure 8.18 illustrates this.

click to expand
Figure 8.18: Client and queue configuration in the first sample.

At this point, the messages that will be used with the queues are simple text messages.

Accessing the MSMQ Web Service Interface with a .NET Client

The .NET client (the code for which can be found in the Client.cs file in the dotNETClient subdirectory) works by first defining the paths of the two queues.

 String purchaseQueuePath = @".\private$\stockpurchases"; String saleQueuePath = @".\private$\stocksales"; 

After these declarations follows the definition for the MSMQInterop Web service itself. This definition is stored in the proxy file, MSMQInteropService.cs. It was generated by using the WSDL.EXE tool from the command line.

 MSMQInteropService msmqAPI = new MSMQInteropService(); msmqAPI.Credentials      = System.Net.CredentialCache.DefaultCredentials; 

Notice how the credentials are set to use the default credentials of the logged- on user. The next step is to create the message to be sent to the purchase queue. A new message of type MSMQInterop.Message is created and populated with some values.

As with the Web service, the message class (Message.cs) has been created by using the XSD.EXE tool that was discussed in Chapter 3. This ensures that you have a compatible data type to exchange between the client and Web service.

 MSMQInterop.Message message = new MSMQInterop.Message(); message.Label = "Stock Purchase"; message.Body = "Imagine this is a stock purchase sent at "     +System.DateTime.Now.ToString(); 

Using this message, the Send method from the Web service is then called to send the message to the purchase queue:

 msmqAPI.Send(purchaseQueuePath,message); 

At this point, the message is sent to the purchase queue. Notice how the Send method returns void (nothing). You might imagine a scenario in which an ID or "receipt" is returned to the caller. We'll look at how to take advantage of this in a moment, when we extend the sample and discuss using a Java client to access an MSMQ Web service interface.

In the final piece of the sample code, the IsQueueEmpty method is used to see whether the sales message queue contains any messages for retrieval. If it does, each message is extracted in turn and displayed on the screen:

 if (msmqAPI.IsQueueEmpty(saleQueuePath)) {     Console.WriteLine("There are no messages on the "         +"Stock Sale Queue."); } else {     while (!msmqAPI.IsQueueEmpty(saleQueuePath))     {         MSMQInterop.Message incomingMessage              = msmqAPI.Receive(saleQueuePath,0);         Console.WriteLine("Message Received...  "             +incomingMessage.Label+": "+incomingMessage.Body);     } } 

Compile and run the code to test. Upon running, the .NET client sample should display text similar to the following:

 Sending a message to the Stock Purchase Queue... There are no messages on the Stock Sale Queue. 

This indicates that the message was successfully sent to the purchase queue and that there were no messages for retrieval from the sales queue.

Accessing the MSMQ Web Service Interface with a Java Client

Now let's look at the Java client. As with many of the samples shown so far in the book, a lot of the .NET and Java client code tends to be similar, and this sample is no exception.

As with the .NET sample, define the queue paths at the start of the class (Client.java in the JavaClient subdirectory), define the URL of the Web service, and set the security for accessing the .NET Web service:

 String purchaseQueuePath = ".\private$\stockpurchases"; String saleQueuePath = ".\private$\stocksales";         String url = "http://localhost/MSMQInterop/Service1.asmx?WSDL"; Context context = new Context(); context.setProperty("authUser","domain\user"); context.setProperty("authPassword","password"); 

With the Java client, you need to specify a username and password to authenticate with the Web service. (Again, this was the primary reason that basic authentication security had to be applied on the Web service.) To get this sample working, replace the domain\\user and password settings with credentials that work in your own environment. These credentials will need read and write access to the MSMQ queues.

As with the .NET client, the Java client calls the Web service, constructs a new message type (again generated from that XSD), sends the message to the sales queue, and retrieves any messages that are within the purchases queue:

 IMSMQInteropServiceSoap msmqAPI      = (IMSMQInteropServiceSoap) Registry.bind(url,         IMSMQInteropServiceSoap.class,context);              Message message = new Message(); message.Label = "Stock Sale"; message.Body = "Imagine this is a stock sale sent at "     +Calendar.getInstance().getTime().toString();              System.out.println("Sending a message to the Stock Sale Queue..."); msmqAPI.Send(saleQueuePath,message);              if (msmqAPI.IsQueueEmpty(purchaseQueuePath)) {     System.out.println("There are no messages on the "         +"stock purchase queue."); } else {     while (!msmqAPI.IsQueueEmpty(purchaseQueuePath))     {         Message incomingMessage              = msmqAPI.Receive(purchaseQueuePath,0);         System.out.println("Message Received...  "             +incomingMessage.Label+": "+incomingMessage.Body);        } } 

After the username and password fields have been adjusted to reflect your own settings, build and run the Java client code. Observe that the Java client sends a message to the sales queue and retrieves the last message that was sent to the purchase queue by the .NET client we recently ran:

 Sending a message to the Stock Sale Queue... Message Received...  Stock Purchase: Imagine this is a  stock purchase sent at 3/17/2003 9:56:56 PM 

Notice how the incoming message is a stock purchase and contains the time that it was sent by the .NET client.

To complete the sample, return to the .NET sample code and rerun the client. Again, you'll see that the .NET client sends a new purchase message to the purchase queue, but this time, the last sale message will be retrieved:

 Sending a message to the Stock Purchase Queue... Message Received...  Stock Sale: Imagine this is a stock  sale sent at 3/17/2003 10:09:38 PM 

Extending the Sample

In the previous sample, you saw how a potential Web service interface for MSMQ can enable messages to be sent to and from different queues, by using either a .NET client or a Java client.

Although this demonstrates how a Web service can act as a faade to an MSMQ interface, you might want to expand the sample in a number of ways:

  • Change the interfaces to be more representative of the business processes The Web service interfaces that we have been using mimic the MSMQ interfaces. These include calls for sending and receiving messages, supplying the path each time. Although this is technically correct, the premise behind Web services is to generally offer business-type services that others can consume ”not strict APIs.

  • Change the security model The previous samples used and relied on the security of the transport itself ”providing the username and password as part of the call and then having the Web service impersonate the client based on these credentials. Again, although this is technically accurate, in a production system, you might want to think about authenticating against another system ”one that's not necessarily dependent on the Windows domain model.

  • Pass across a "real type" Until now, we've exchanged fictitious messages about purchases and sales of stocks. However, we need to use a complex type that will more accurately describe the data moving between the Java and .NET platforms via MSMQ.

To demonstrate the items in this list, look at the sample code in the C:\Interoperability\Samples\Resource\MSMQ\WebServiceAPI directory. In addition to the previously discussed Simple Web service example, this directory contains two subdirectories, ExtendedWebService (which is the Web service that supports the items in this list) and ExtendedClients.

If you first look at the methods exposed by the Web service (Service1.asmx.cs), you can see some of the main differences between this sample and the previous one. Instead of exposing Web service APIs that mimic the send and receive APIs of MSMQ, these methods are much more aligned to the task at hand:

 public String CreateStockPurchase(StockRecord record,      Credentials creds) public String CreateStockSale(StockRecord record,      Credentials creds) public StockRecord GetNextStockPurchase(Credentials creds) public StockRecord GetNextStockSale(Credentials creds) 

The code contains two methods that allow new stock purchases and sales to be created, and two other methods that allow the stock purchases and sales to be retrieved from the queue. Notice that each of the methods requests a parameter for credentials. This again differs from the previous example. Here, you forward the security details with the method of the Web service, instead of relying on the authentication mechanisms of the underlying transport (HTTP).

To simulate the other authentication model, the Web service has a class named Authenticator . This class accepts credentials and returns a Boolean value based on their validity. You can imagine how in a production system, this class can be used to call some external or shared authentication mechanism.

Finally, notice how all the methods used to create new sales or purchases accept a record of type StockRecord . Within the class, an XML serialization process is used to serialize this StockRecord class to an XML document. The XML document then makes up the body of the MSMQ message. This message uses the same serialization techniques discussed in Chapter 3.

To configure the Web service, build the code in the C:\Interoperability\Samples\Resource\MSMQ\WebServiceAPI\ExtendedWebService directory. Create a new IIS virtual directory with an alias of MSMQInteropExt that points to the sample code. This virtual directory can be set up for anonymous access, which is the default setting.

Because the authentication provided by HTTP and IIS isn't being used in this sample, you might need to set the appropriate permissions in the two queues. This is required because the account that the Web service is running under needs write permission to these queues. If you followed the "Configuring ASP.NET Security" section in Chapter 1, "Microsoft .NET and J2EE Fundamentals," you don't need to do anything because the process is running under the context of the SYSTEM account.

Note

If ASP.NET is running under an alternative or restricted account (which would be recommended for production purposes), you'll need to apply the appropriate permissions for the queues. To do this, open the Computer Management console and locate the purchase and sales queues. In turn, right-click each of these, select the Properties menu item, and navigate to the Security tab, as shown in Figure 8.19.

Next, add and grant full permission to the queues for the account that ASP.NET is running under. (You might have to explicitly add this user account to the list of users.) The default for this will be ASPNET. If you're running the ASP.NET process under another account, select that account.

click to expand
Figure 8.19: Enabling the ASP.NET account to access the queues in the extended sample.

Browse to http://localhost/MSMQInteropExt/Service1.asmx to validate that the new sample Web service is running, as shown in Figure 8.20.

click to expand
Figure 8.20: The deployed Web service, MSMQInteropExt.

Accessing the Extended Sample with a .NET Client

To show the extended sample in action, two slightly different clients have been created. The .NET client acts as a stock trade monitor, listening for stock records that are placed in the queues. The Java client actively places such records in the queues.

The .NET sample client, which can be found in the C:\Interoperability\Samples\Resource\MSMQ\WebServiceAPI\ExtendedClients\dotNETClient directory, runs as a Windows Forms application. Build the sample in this directory by using NAnt, and type client from the command prompt to launch the application. The application shown in Figure 8.21 will be displayed.

click to expand
Figure 8.21: The Windows Forms sample application, which monitors the stock purchases and sales.

The sample client displays the two queues (purchases and sales) and has a check box to stop and start monitoring of the queues. This monitoring is performed by using a polling approach, where the GetNextStockPurchase and GetNextStockSale methods of the Web service are called by using two separate threads within the application (to prevent the application from being blocked by the calls). If nothing is available from either of the queues, the thread sleeps for a predetermined amount of time and retries the operation when that time frame has elapsed. Once an item is discovered in the queue, the appropriate thread will raise an event that's caught by the form itself.

Looking through the code, you'll also notice the agent-service pattern that was discussed in Chapter 6. This pattern (which can be found in StockMonitorAgent.cs) is used to abstract the underlying Web service proxy class and manages the passing of the authentication credentials.

Accessing the Extended Sample with a Java Client

Now that we have the Web service deployed and the .NET Windows Forms client listening for incoming messages, let's generate some sample stock sales and purchases by using the Java client. The Java client sample, found in the JavaClient subdirectory, contains the Web service proxy files to consume the extended Web service. Within the code (Client.java), a new sample stock sale and purchase is created and sent to the Web service.

You might notice that the new Web service calls return a string, shown in the following code:

 String purchaseReceipt = qs.CreateStockPurchase(purchase,creds); 

When the Web service writes the stock record to the queue in MSMQ, the ID of the MSMQ message is returned to the client. This ID is a globally unique identifier (GUID) followed by a sequence number and is automatically generated by the MSMQ API.

Compile and run the Java client code. Upon successful completion, the client displays the confirmation of the two actions ”your receipt strings will be different:

 Purchase entered successfully.     Receipt is: 5ede193e-f0d9-4b1e-9c2a-0be3fb1cd6ff Sale entered successfully.     Receipt is: 5ede193e-f0d9-4b1e-9c2a-0be3fb1cd6ff 

If you now switch to the .NET Windows Forms client (or open the client, if it's not already running), you should see the two entries recorded, as shown in Figure 8.22.

click to expand
Figure 8.22: The .NET stock monitor, asynchronously receiving incoming records from the Java client.

The clear difference between this demo and the last notification demo in Chapter 7 (where the Java DAO updated the .NET equivalent) is the asynchronous nature of the call. In the Chapter 7 example, in which the .NET client was notified by the DAO of an update to the database, the .NET client had to be online to respond. Here, you can close or disable the monitoring in the .NET client and rerun the Java client, and the message will still reach the .NET client when it's reopened.

Web Service Interface to MSMQ ”What You Lose

In this chapter, you've seen how to build a Web service interface for MSMQ and send both simple and serialized messages between the .NET and Java platforms. Although this provides a neat way of exchanging asynchronous messages between the two platforms via the Web Services model, for a number of reasons, this approach certainly isn't nirvana for enterprise messaging. Certain features included in MSMQ are difficult to replicate with an additional Web services interface layer. These features include reliable messaging, transactions, and true callback.

Reliable Messaging

Reliable messaging is the art of sending a message and ensuring that it either reaches its destination or doesn't ”and knowing which of these states occurred.

One of the problems with trying to guarantee reliable messaging by using Web services is the transport itself, HTTP. HTTP was designed to run primarily as an Internet-based protocol ”the Internet being a network of potentially slow and unreliable connections. As a result, many implementations and providers of the HTTP protocol contain a certain element of " retry " logic. For example, if you've ever had a bad connection to the Internet over a dial-up line, you might have noticed that some pages and images appear to pause when downloading. In a lot of these cases, this ability to continue without immediately throwing an error is the result of an intentional design choice of the HTTP protocol itself.

Based on this, using HTTP for reliable messaging can have some consequences. For example, using the previous stock-trading scenario, imagine this example: Alice, a user of your system, uses the Web service interface API for MSMQ sample demonstrated throughout this section to place an order to buy stock. The order is for $1 million worth of shares. In her share-dealing client software, Alice enters the details of the trade and presses the Commit button.

Alice's client software constructs a Web service request, similar to the Java client request presented earlier, and submits the message to the Web service interface, as shown in Figure 8.23.

click to expand
Figure 8.23: A request from Alice to purchase $1 million worth of shares.

The message successfully reaches the Web service. To confirm that the Web service request was accepted, the Web service sends an HTTP 200 ACCEPT message to the client. This is default behavior of the HTTP protocol. Imagine, however, that at this point in time, a temporary network failure occurs. The HTTP 200 ACCEPT message is never returned to Alice's client, as shown in Figure 8.24.

click to expand
Figure 8.24: The acknowledgment for the purchase never reaches Alice.

As mentioned, Alice's Web service client never receives the HTTP 200 ACCEPT message from the Web Service. Thinking that a network error has occurred, the client automatically resends the Web service request (to purchase the order of $1 million worth of shares). It could be either a feature of the HTTP provider on the client or something in Alice's client software that resends the request.

Now that network connectivity has been restored, the message reaches the destination and an HTTP 200 ACCEPT message is successfully returned to the client. The problem here is that the Web service has received two messages requesting a $1 million order for Alice, whereas Alice (and her client software) believes that only one order has been placed! Subsequently, $2 million is withdrawn from Alice's account, as Figure 8.25 depicts.

click to expand
Figure 8.25: Thinking that the send failed, Alice's client software resends the purchase.

Preventing this type of situation from occurring when using HTTP requires a solution that uses messages classified as idempotent . Idempotent is defined as something that's unchanged when multiplied by itself.

In this example, because HTTP is the transport of choice, you have to use a solution that uses idempotent messages. That way, regardless of how many times the Web service receives the $1 million order message from Alice, the system will have to recognize that just a single order was placed. This can be achieved by using a unique message ID that's generated by the client. Imagine if when Alice places her order, the client passes a unique ID with her request, as shown in Figure 8.26. Business logic on the server can determine whether the message ID has already been received and can ignore or process it accordingly .

click to expand
Figure 8.26: Alice adds unique message IDs to help avoid duplication.
More Info

This discussion has merely presented an introduction to dealing with idempotent messages and reliable messaging in general. For additional information and research on this and other elements of autonomous computing, I recommend starting with this webcast on the topic, given by Microsoft Architect Pat Helland: http://www.microsoft.com/usa/Webcasts/ondemand/892.asp .

Looking ahead to WS-Reliable Messaging

Today's Web services offer a great way to achieve interoperability between points in a distributed architecture. I hope that the samples and chapters you've seen so far have illustrated this. Interoperability using Web services is really about connectivity ”the ability to connect one client, application, or service to another.

As we've delved deeper into Web services, it's become clear that the Web services stack lacks certain functionality ”which I define as application-specific interoperability. As you've seen in this section, reliable messaging is one of these limitations.

A number of members of the Web Services Interoperability Organization (WS-I) are developing specifications to overcome some of these shortfalls. (I call these the WS-* specifications because they all begin with this prefix.) At the time of this writing, many of these specifications are still in draft, but we are now seeing some actual implementations being released.

One of these specifications, WS-Reliable Messaging , was coauthored by Microsoft, IBM, BEA, and TIBCO. The specification itself defines a modular mechanism for implementing reliable messaging over Web services. It defines a protocol that identifies, tracks, and manages a message between two points. This is performed by a number of defined SOAP headers and bindings.

This specification, which can be found at http://msdn.microsoft.com/ webservices /default.aspx?pull=/library/en-us/dnglobspec/html/ws- reliablemessaging.asp , demonstrates some of the work that's being addressed in this area.

Transactions

In addition to reliable messaging, enterprise message queues are renowned for their transactional qualities ”in other words, their ability to send messages to multiple queues as part of a single transaction. As with reliable messaging, transactions are difficult to incorporate into the Web services model.

Again, this is best described with a small example. Suppose that after spending so much money on her stock shares, Alice decides that she needs to move money from her checking account into her share-dealing cash account. Moving this money from her checking account to her share-dealing account is a transaction. The debit from Alice's checking account and the credit to her share-dealing account must complete ”or both must fail ”for the transaction to be valid.

Alice wouldn't want to debit the money from her checking account if, for some reason, it could not be placed into her share-dealing account. Likewise, the bank will want to ensure that the checking account is properly debited the amount of the funds moved to the share-dealing account. Both sides of the operation must succeed for the transaction to be valid.

MSMQ 3.0 supports the ability to create transactional message queues to handle situations similar to this example. Recall how at the start of the chapter, in Figure 8.7, we had the option of specifying whether a queue was transactional.

To see these types of transactions in action, create two new private queues using the Computer Management console. Name them checkingaccount and shareaccount , and mark them both as transactional, using the check box shown in Figure 8.27.

click to expand
Figure 8.27: Creating a transactional queue in MSMQ.

Once done, look at the sample code located in the C:\Interoperability\Samples\Resource\MSMQ\Transactional directory. This sample code in Client.cs creates two messages as part of a transaction: one to the checking account (to instruct the debit), and one to the sales account (to inform it of a credit).

The transaction is managed by a class in the System.Messaging namespace named MessageQueueTransaction , defined by the following piece of code:

 MessageQueueTransaction mqt = new MessageQueueTransaction(); 

As part of a try catch block, the transaction is started. The various send methods used to send the messages to MSMQ include the reference to the previous MessageQueueTransaction . Notice how the debit message is sent to the checking account and the credit message is sent to the share-dealing account.

 try     // Start the transaction     mqt.Begin();     // Send the messages     checkingMQ.Send(debit,mqt);     shareMQ.Send(credit,mqt);                      // Nothing went wrong - commit the transaction     mqt.Commit();     Console.WriteLine("The transaction completed successfully."); } 

If nothing goes wrong with the transaction, both messages are placed in the queue by using the Commit method. If, however, something does fail, this is caught in the catch block of the code:

 catch (Exception e) {     Console.WriteLine("An exception occured as part of the "         +"transaction. "+e.ToString());     Console.WriteLine("Aborting the transaction...");     mqt.Abort(); } 

The exception is reported to the user, and the Abort method is used to stop the transaction. If the transaction is aborted, no messages will be written to either queue.

Now compile and run the code. If all is successful, the transaction will complete and two messages (one per queue) will be available in the transactional versions of the queues that were just created. Note that you might need to refresh the queue for the message to be displayed.

Now we'll make the transaction fail. Purge the two queues by right-clicking Queue Messages and selecting All Tasks/Purge. Step back into the code, and locate the following line:

 MessageQueue shareMQ = new MessageQueue(@".\private$\shareaccount"); 

Change the path of the share-dealing account queue to something that doesn't exist (for example, ".\private$\doesnotexist") . Recompile and rerun the sample.

The message to debit the checking account will succeed. The message to credit the share-dealing account, however, fails (because no queue with that name is found). This error is caught in the catch block of the code. Because all these operations form part of a transaction, everything is aborted (including the previous debit from the checking account). The result is the following exception and abort message from the client:

 An exception occurred as part of the transaction.  System.Messaging.MessageQueueException:  Queue is not registered in the DS.     at System.Messaging.MessageQueue.ResolveFormatNameFromQueuePath(     String queuePath, Boolean throwException)     at System.Messaging.MessageQueue.get_FormatName()     at System.Messaging.MessageQueue.SendInternal(Object obj,      MessageQueueTransaction internalTransaction,      MessageQueueTransactionType transactionType)     at System.Messaging.MessageQueue.Send(Object obj,      MessageQueueTransaction transaction)     at dotNET.Client.Main(String[] args) Aborting the transaction... 

In addition, nothing will be written to either of the transactional queues.

So how does this all relate to the MSMQ Web service API that we created? And why is it difficult to create a transactional call using the Web service API? To achieve the results from the previous example, you need to create the transaction, send the messages, and then either commit or abort. This process requires a number of actions, whereas the Web service API is only capable of dealing with a single action at a time. The Web service is stateless, which means that no affinity is held between the client and the service. The Web service takes a single action (for example, sending a message to a certain queue), acts upon it, and is then complete.

To perform a transaction, you need to perform a number of related actions. To do this, you need to create some session state on the Web service. This state would hold the number of requests as they're received and then process them as part of a transaction that runs on the Web service, as shown in Figure 8.28.

click to expand
Figure 8.28: Dealing with transactional state using Web services.

Storing state with a Web service is technically possible, but a number of valid arguments against doing so exist. These include

  • Jeopardizing the ability to scale Multiple instances of Web services running with state can cause heavy load.

  • Possible denial-of-service attacks Multiple Web services are called; all create and hold state, using valuable memory and resources.

  • Failover What happens when a Web service fails halfway through creating a transaction?

Looking ahead to WS-Transaction

In addition to WS-Reliable Messaging, another specification that addresses some of the application interoperability challenges of Web services is WS-Transaction. The latest version of this specification, which can be found at http://msdn.microsoft.com/webservices/understanding/gxa/default.aspx?pull=/library/en-us/dnglobspec/html/ws-transaction.asp , defines both atomic transactions and business activities.

An atomic transaction is typically short lived and is used to identify an operation that must exhibit ACID (atomic, consistent, isolated, and durable) attributes. In an atomic transaction, all operations either complete successfully or are rolled back in the event of an error or exception. The previous example demonstrated an atomic transaction. A business activity is a long-running transaction that involves compensations. Business activities are typically used in situations where atomic transactions do not apply.

For example, let's reexamine Alice's bank balance. The reliable messaging discussion mentioned that Alice's bank balance had been withdrawn twice by accident ”as a result of the Web service receiving the message a second time. If this had been the case, Alice would have contacted her bank to have the error fixed. Once realizing that they were at fault, it's likely that the bank wouldn't have scrubbed the withdrawal from Alice's records (because this could cause inconsistencies with statements issued). Instead, they would have recredited her account with the $1 million to correct the error. This type of transaction rollback (or abort) is known as a compensating transaction and is well defined in the scope of a business activity.

I recommend reading through the current WS-Transaction specification. This will give you an appreciation of the topic, the problems you face when making transactions, and the work that's being done to improve the use of transactions in Web services.

True Callback

The final area that isn't truly addressed by the MSMQ Web service wrapper has to do with true callback. You might have noticed that in all the samples shown in this chapter, receiving a message is always controlled by the client. It's the responsibility of the client to "poll" the message queue and see whether a message is waiting.

As a developer, there are certain actions you can take to make this polling a little more asynchronous. This includes using the AsyncCallback methods investigated at the start of the chapter. In addition to this type of callback being valid for Web services, it's supported in the System.Messaging class through the BeginReceive and EndReceives methods of the MessageQueue class.

But is this true callback? Technically, it isn't. Although the callback is made through a second thread to prevent blocking of the client, this callback is still a request-response type of operation and has to utilize the polling approach as before. This is similar to how the previous MSMQ transaction example worked and is shown in Figure 8.29.

click to expand
Figure 8.29: Web services polling approach used in the previous MSMQ transaction example.

In this case, the client is still polling, which generates additional (and arguably unnecessary) network traffic. A more ideal solution to enable a true callback is for the queue to notify the client when a message is ready to be collected, as shown in Figure 8.30.

click to expand
Figure 8.30: What's required for a true callback notification.

Generally in message queue technology, true callback can be achieved by giving the queue a callback location when connecting or sending a message. The queue registers the client and sends notifications directly when messages that match certain criteria enter the queue. Another option is to use a multicast protocol ”based on User Datagram Protocol (UDP) ”to widely distribute the notification to any client that happens to be listening. To facilitate this, MSMQ 3.0 supports the Pragmatic General Multicast (PGM) "reliable multicast" protocol.

Unfortunately, this is difficult, if not nearly impossible, with Web services today. The underlying reason is again that Web services are based on HTTP, request-response interactions. Callback notifications using these methods with just a regular Web services client is impossible . This is because the Web services client can only issue requests and waits for a response to these requests ”and therefore, has no ability to independently "listen" for incoming messages. Of course, it's possible to set up a Web services server component on the client itself (to listen for incoming requests), but then you face potential issues with firewalls and Network Address Translation (NAT).

The underlying problem is that today Web services rely on the HTTP request-response communication model. As the development community moves forward with new implementations of Web services, I think we'll start to see the Web services stack decoupled from the transport. Once this becomes an accepted practice, true callback in asynchronous Web services applications will be more of a reality.




Microsoft. NET and J2EE Interoperability Toolkit
Microsoft .NET and J2EE Interoperability Toolkit (Pro-Developer)
ISBN: 0735619220
EAN: 2147483647
Year: 2003
Pages: 132
Authors: Simon Guest

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net