Interoperability Technologies: Data Tier
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
Summary: Concentrates on techniques that apply to the Data or Resource tier. Techniques covered include shared databases and asynchronous message queuing. Finally, this chapter briefly covers other asynchronous techniques such as using the MSMQ-MQSeries Bridge in Microsoft Host Integration Server.
Chapter 4, "Interoperability Technologies: Point to Point," describes implementing point to point interoperability techniques, such as .NET Remoting and Web services. This chapter covers technologies that can help you implement connectivity between .NET Framework and Java applications at the Data tier such as database connectivity and asynchronous connectivity through message queuing.
One interoperability scenario is where you have an existing data repository that you now want to access from both .NET Framework and Java applications. This chapter considers the implications of such a setup together with best practice recommendations for creating shared databases.
.NET Remoting and Web services provide the ability to link either tightly or loosely coupled systems on intranets or across the Internet. However, these techniques cannot cope with environments that must withstand very high latency levels or non-permanent connections, for example, the increasing use of handheld devices connected through some form of wireless link. Asynchronous methods can overcome issues of non-permanent links.
You may have the situation where you have two applications, on different platforms, that you want to share the same underlying database. This configuration addresses the issue of maintaining multiple data stores. Sharing a database between .NET Framework and J2EE applications is a simple and effective means of implementing interoperability between the two environments.
Figure 5.1: .NET Framework and J2EE applications sharing a common database
The technologies that enable you to do this are not new. Both platforms have had mechanisms to implement database connectivity since they started. The existence of database drivers makes it easy for you to link Business tier applications to a common back-end storage and share tables, records, and fields between platforms.
Both platforms provide links into multiple databases, such as Microsoft SQL Server®, Oracle, Informix, MySQL and DB2. This section discusses the ways that both .NET Framework and Java applications connect to databases, as well as some best practices for sharing databases.
Before you can learn how to share databases, you need to appreciate how each platform connects to a database. Each platform has a built-in data access API:
- ADO.NET in the .NET Framework.
- JDBC in Java.
For the majority of implementations, your choice of database and platform should not be a factor.
Note Although the samples in this section refer to SQL Server 2000, the strategies shown apply to all databases.
Connecting with JDBC
JDBC is the API that enables J2EE applications to access tables, records, fields and stored procedures in any compatible database. You can use JDBC to connect to almost any tabular data, including spreadsheets and information in flat file format.
JDBC 3.0 represents the most recent release of the specification, which a variety of vendors now endorse, including IBM, Hewlett-Packard, BEA, Simba, and Oracle. Sun has recently filed JSR221, which covers the JDBC 4.0 API specification.
Note Java 2 Platform, Standard Edition (J2SE) 1.4 includes complete support for JDBC 3.0, located in the Java.sql and Javax.sql packages. The classes and interfaces in these packages allow Java applications to access any database for which they have a JDBC database driver.
There are four types of JDBC database drivers:
- Type 1 (JDBC to ODBC bridge with ODBC driver) Type 1 drivers provide JDBC access through ODBC drivers. Sun supplies a JDBC to ODBC bridge driver in the J2SE that you can use if no other driver is available. Type 1 drivers require native code installation on the client computer.
- Type 2 (Native API with Java technology driver) Type 2 drivers convert JDBC calls into calls to the client API. As with Type 1 drivers, this implementation requires native code installation on the client computer.
- Type 3 (Pure Java driver for database middleware) Type 3 drivers translate the JDBC calls into a middleware vendor's protocol. The middleware then translates this protocol into DBMS calls. You do not have to install any native code on the client computer, but you must specify security configuration settings for Internet operation.
- Type 4 (Pure Java direct to database driver) Type 4 drivers translate JDBC calls into DBMS calls directly, and use native protocols to access the database.
Note Type 4 "Pure Java" drivers are the preferred option because they typically offer the best performance.
JDBC uses the concept of ResultSets. A ResultSet is a grouping of all the rows that satisfy the conditions within a SQL statement. You can access the data in the ResultSet using the get method, which enables you to traverse columns in the current row. You can also move to the next row using ResultSet.next.
Applications can execute statements and then process any number of result sets. The statement that generates a ResultSet automatically closes it, either by closing the statement, executing it again, or retrieving the next result from multiple result sequences.
Note ResultSets are similar to ADO.NET DataSets. However, ResultSets are closer to ADO RecordSets, the pre-.NET database access API objects.
Connecting to SQL Server 2000 with JDBC
You can access SQL Server 2000 from Java applications using any one of a range of JDBC drivers, either free or commercial in nature. For example, Microsoft provides the Microsoft SQL Server 2000 Driver for JDBC Service Pack 1. This is a Type 4 JDBC driver that provides highly scalable and reliable connectivity for J2EE applications. This driver provides JDBC access to SQL Server 2000 for any Java-enabled applet, application, or application server.
For more information about the Microsoft SQL Server 2000 Driver for JDBC Service Pack 1, including download information, go to the Microsoft Download Center.
Note When connecting to SQL Server 2000 using a JDBC driver, ensure the security settings on SQL Server use SQL Server and Windows authentication (mixed mode authentication). Also, ensure that you set a complex (mixed case letters and numbers) password for the sa account.
For more information about connecting to SQL Server 2000 with the Microsoft JDBC driver, see Microsoft Knowledge Base article Q313100, "HOW TO: Get Started with Microsoft JDBC."
Connecting with ADO.NET
Accessing data in relational databases has always been a feature with Microsoft platforms. Before the arrival of the .NET Framework, ActiveX Data Objects (ADO) API was the primary database access mechanism. The .NET Framework introduced ADO.NET as the new API for connecting to databases on Microsoft platforms.
ADO.NET represents the abstract design concepts that you need to build data access classes within the .NET Framework. ADO.NET lets you work with data irrespective of data source, data format, or physical location. It includes a new object model and promotes new concepts such as the DataSet and the DataReader classes.
ADO.NET improves on ADO by being less database-centric and more aligned with modern Web service based programming. It works well in a distributed environment and enables developers to link to data sources quickly and reliably.
There were several main design goals for ADO.NET:
- Explicit and factored object model ADO.NET provides a simple to use object model in which developers have complete control over how to control data source connectivity, command execution, and data manipulation.
- Disconnected data cache model N-tier programming and XML Web service architectures require that applications work in a disconnected, loosely coupled manner. ADO.NET provides a comprehensive caching data model for marshaling data between applications or services and then updating the original data source.
- Common data representation with data combination ADO.NET gives you the ability to combine data from multiple and varied data sources.
- XML support XML is a key component in building interoperable applications and more robust data processing models. ADO.NET uses the XML support in the .NET Framework by interacting with XML in either a relational manner or in native XML.
- Use existing ADO knowledge Although the ADO.NET object model differs from the previous ADO model, the basic constructs remain the same. The ADO.NET object model consists of a provider, connection, and command objects, enabling current ADO developers to migrate easily to ADO.NET.
From a developer's perspective, ADO.NET represents the concrete implementation of classes inside the .NET Framework that you can use for data access. These classes exist within the System.Data namespace of the .NET Framework.
Note The ADO.NET classes in System.Data.dll are integrated with the XML classes found in System.Xml.dll. Hence to compile code that uses the System.Data namespace, you should add a reference to both System.Data.dll and System.Xml.dll in your Visual Studio .NET projects.
ADO.NET introduces the concepts of datasets, as provided by the DataSet class. You can compare a dataset to a ResultSet object in JDBC, but datasets provide a disconnected view of the data. You can take datasets offline, modify them, and then update the database with the amended values.
ADO.NET also introduces the concept of data readers, as provided by the SqlDataReader, OleDbDataReader, and OracleDataReader classes. A data reader object retrieves a read-only, forward-only stream of data from a database. You can use the data reader object to increase application performance and reduce system overhead as only one row at a time is held in memory.
To determine whether to use a dataset or data reader when you design your application, consider the level of functionality that you need in the application.
Use a dataset in order to do the following:
- Navigate between multiple discrete tables of results.
- Manipulate data from multiple sources (for example, a mixture of data from more than one database, from an XML file, and from a spreadsheet).
- Exchange data between tiers or using an XML Web service. Unlike data readers, you can pass a dataset to a remote client.
- Reuse the same set of rows to achieve a performance gain through caching (such as when sorting, searching, or filtering the data).
- Perform a large amount of processing per row. Extended processing on each row returned using a data reader ties up the connection serving the data reader longer than necessary, affecting performance.
- Manipulate data using XML operations such as Extensible Style Language Transformations (XSLT transformations) or XPath queries.
Use a data reader in your application for the following reasons:
- You do not need to cache the data.
- You are processing a set of results too large to fit into memory.
- You need to access data quickly and once only, in a forward-only and read-only manner.
ADO.NET connects to a database through managed providers. These are database drivers that expose APIs using classes operating from managed code. You can obtain managed providers for SQL Server, Oracle 8i, MySQL and IBM's DB2, as well as several other databases.
Alternatively, managed providers can access OLEDB or ODBC-based drivers. OLEDB and ODBC are two older database-independent connection APIs that you can use to connect to any compliant data store. If you use the ADO.NET managed provider for either of these APIs, you can access virtually any database with one set of code; however, you add the overhead of another API layer.
The managed providers for each database (such as the managed provider for SQL Server 7.0 or SQL Server 2000) link directly to the database at the binary level, giving a substantial performance advantage. For this reason, you are recommended to use the managed provider for the database you are connecting to instead of the more generic OLEDB or ODBC-based drivers.
Using the managed provider for a particular database does imply that your application is then tied to that database and switching to another database would require rewriting the database access code. However, it is rare for an organization to change its database, and it is certainly not something that companies do just for fun. Hence the performance benefits are worth the minor inconvenience of dedicated database access code.
Note There are techniques in this chapter that cover how to enable your application to use different databases without significant code rewriting.
Connecting to Microsoft SQL Server 2000 with ADO.NET
You can access SQL Server 2000 from .NET Framework applications through the SQL Managed Provider for ADO.NET. You can find most of the APIs you need to access the SQL Manager Provider for ADO.NET in the System.Data.SqlClient namespace. This is the namespace that you import at the beginning of your code.
The Connection, Command, Data Reader, and Data Adapter objects provide the core functionality of the ADO.NET data provider model. Each managed provider provides its own implementation of these core objects prefixed with the provider name. For example, the SQL Managed Provider for .NET Framework contains classes such as SqlConnection and SqlCommand. ADO.NET classes prefixed with Sql address the SQL Server managed provider and only work with SQL Server.
Using these SQL Server managed provider classes offers two major advantages over their OLE DB provider counterparts. Firstly, these classes use the native Tabular Data Stream (TDS) interface for maximum performance and the additional interface layers that the OLE DB classes require no longer exist, resulting in faster database access. Secondly, the SQL classes that these controls create have additional methods that take advantage of features specific to SQL Server. This provides you with greater flexibility in design and programming with SQL Server.
In a simple connection scenario, you can use objects in the following manner. First, you define a connection to the database using the SqlConnection class. This class builds a connection string including the computer name, database name, and authentication details, such as user name and password. You then use the Open method to open the connection to the database.
To fetch data from the database, you construct a SqlCommand object that contains the relevant select statement. The ExecuteReader method called on the SqlCommand object returns a SqlDataReader object containing the results from the select statement. Finally, you extract the fields from the reader, index them with the GetValue method and use them however you want within the application. For more information about implementing these commands, see the References section at the end of this chapter.
Sharing Data Between ADO.NET and JDBC
You have seen how both JDBC and ADO.NET provide database connectivity for .NET Framework and J2EE applications to a range of databases. You should now appreciate that both environments can point to a single data source to add, read, update, and delete records. It is now time to look at some best practices for implementing database connectivity.
Abstracting database access code from the rest of your application is best practice in both .NET Framework and J2EE application architectures. For ease of coding and consistency, you should implement a layer that abstracts the database code from the business logic, as Figure 5.2 shows.
Figure 5.2: The Data Access Logic Components abstract the database code from the Business tier
This abstraction pattern has different names depending on the platform. In J2EE, this is the Data Access Object (DAO) pattern. The Application Architecture for .NET: Designing Applications and Services guide refers to this as Data Access Logic Components or simply Data Access Logic. The next section looks at the benefits of implementing a Data Access Logic layer in both .NET Framework and J2EE applications.
Note This book refers to the Data Access Logic Components pattern for both .NET and Java applications.
Implementing Data Access Logic Components
Regardless of the data store you choose, your application should use Data Access Logic Components to access the database. These components abstract the semantics of the underlying data store and data access technology (such as ADO.NET or JDBC) and provide a simple programmatic interface for retrieving and performing operations on the stored data.
Data access logic components usually implement a stateless design that separates the business processing from the data access logic. Each data access logic component typically provides methods to perform create, read, update, and delete (CRUD) operations on a specific business entity in the application.
For example, in an e-commerce application, you can design a data access logic component for handling all data interactions with the data relating to customer orders. This data access logic component is not necessarily tied to one table in the database; it can access any of the tables that relate to order data. Typically, this data access logic component retrieves complex data types that represent a business entity, in this case, an OrderData object.
For more information about implementing data access logic, see the References section at the end of this chapter.
Taking this concept further, if you have multiple data access logic components, it is a good idea to implement a database helper class to handle common tasks such as database connections, execute commands, and cache parameters, and so on. The data access logic components provide the logic to access specific business data, while the database helper class centralizes data access API code to a specific database. This helps to reduce code duplication.
You have already seen that if you use a managed provider class to communicate with a database, you may need to write code that is specific to that database. When you implement a database helper class, you can keep all database specific code within that class. The database helper class enables you to keep your data access logic components database independent. Changing database types means simply replacing your database helper class with one that can communicate with the new database. Additionally, environments with more than one database type can use multiple database helper classes in order to access data from the different databases.
Microsoft provides the Data Access Application Block (DAAB) for the .NET Framework, which can be used as a database helper for accessing SQL Server. For more information about the DAAB, including download information, see "Data Access Application Block Overview" on MSDN.
Benefits of Implementing Data Access Logic Components
Implementing Data Access Logic Components gives the following interoperability benefits:
- Creates a common approach for accessing data from either environment, enabling developers to write business logic code with a consistent feel regardless of the underlying platform.
- Provides the ability to abstract access to different underlying databases.
- Enables the integration of further logic and processes for accessing databases, such as:
- Caching for added performance.
- Authentication and authorization for user connections.
- Transaction support and locking.
- Data paging for large results sets.
The common approach benefit opens the door for a further interoperability scenario where the Business tier on one platform can call the Data Access Logic tier of the other platform. This advances the concept of sharing a database between .NET Framework and Java applications by allowing you not only to share the database, but also the data access logic that communicates with the database. The XBikes sample application included in this guide provides the ability to implement this scenario through one of its configuration options.
Figure 5.3: Sharing Data Access Logic Components between .NET Framework and Java applications
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.
Connecting with Web Services Using Asynchronous Calls
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.
Using Callbacks in Client Applications
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.
Using Message Queues for Asynchronous Interoperability
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.
Note In Figure 5.4, the sender and receiver applications may be on different platforms.
Figure 5.4: Example of a message queuing application
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.
Using Microsoft Message Queuing
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.
Choosing Between Private and Public Queues
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
Connecting to MSMQ from .NET Framework 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:
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.
Working with MSMQ Queues
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 Queue Messages
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."
Retrieving Queue Messages
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."
Connecting to MSMQ from J2EE
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.
Using a Java-to-COM Bridge
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.
Using a JMS Provider for MSMQ
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.
Creating a Web Service Interface
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.
Using IBM WebSphere MQ
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.
Administering WebSphere MQ
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.
Accessing WebSphere MQ from a Remote Computer
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.
Understanding the Role of JMS
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.
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.
Connecting to WebSphere MQ from J2EE Applications
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.
Using the WebSphere MQ Classes for Java
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.
Using the WebSphere MQ Classes for JMS for Point-to-Point Messaging
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.
Using WebSphere MQ Classes for JMS for Publish/Subscribe Messaging
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:
- 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.
Connecting to WebSphere MQ from .NET Framework Applications
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.
Using the WebSphere MQ Classes for Microsoft .NET
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 [Content link no longer available, original URL:http://www-3.ibm.com/software/integration/mqfamily/support/summary/wnt.html] 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.
Using JMS and Third-Party Bridging Products
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.
Accessing JMS Messages from .NET Framework Clients
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.
This chapter has described how both MSMQ and IBM WebSphere MQ can enable asynchronous interoperability between .NET Framework and Java clients and you can connect Java clients to MSMQ or .NET Framework clients to WebSphere MQ. However, there are several drawbacks to each technique such as the loss of reliable operations or transactional support.
An alternative way to implement asynchronous connectivity between .NET Framework and Java applications is by linking MSMQ and WebSphere MQ through the use of a bridge. In this approach, the .NET Framework application connects to MSMQ and the Java application connects to WebSphere MQ. You then use a bridge to connect the two queues. Figure 5.12 shows a high-level view of this approach using the MSMQ-MQSeries Bridge that is part of Microsoft Host Integration Server (HIS) 2000.
Figure 5.12: Using the MSMQ-MQSeries Bridge in HIS 2000 to enable asynchronous interoperability
HIS evolved from Microsoft SNA Server and enables organizations to connect Windows and LAN-based networking to host-based mainframe equipment. Most importantly from the interoperability perspective, HIS provides an MSMQ-MQSeries Bridge. By using the native message queue implementations, the bridge guarantees reliability and transactional message queue qualities.
For more information about HIS, see the Host Information Server Web site.
Bridging MSMQ and WebSphere MQ with HIS 2000
The MSMQ-MQSeries Bridge gives HIS the capacity to exchange messages in either direction between MSMQ and WebSphere MQ components. HIS can take messages from MSMQ queues and deliver them to WebSphere queues and back again.
Note The MSMQ-MQSeries Bridge works with IBM WebSphere MQ, even though the bridge product name refers to MQSeries.
The MSMQ-MQSeries Bridge system contains two main components:
- MSMQ-MQSeries Bridge Converts and transmits messages between the MSMQ and MQSeries environments.
- MSMQ-MQSeries Bridge Manager Lets you configure, monitor, and control the messaging traffic through the MSMQ-MQSeries Bridge.
The MSMQ-MQSeries Bridge maps the fields or properties of a message to the corresponding fields or properties of the destination message queuing system. For example, if you send a message from WebSphere MQ to MSMQ, MSMQ-MQSeries Bridge analyzes the fields of the WebSphere MQ message and maps each value to its MSMQ counterpart.
In cases where one system needs an additional field that does not exist in the other, MSMQ-MQSeries Bridge provides the field during the conversion process. For example, suppose that a MSMQ message includes the PROPID_M_TIME_TO_BE_RECEIVED property with a specific value. The MSMQ-MQSeries Bridge maps this property to the MQMD.Expiry WebSphere MQ property and multiplies the value by 10 to change the units from seconds to tenths of seconds.
Note The MSMQ-MQSeries Bridge does not restrict the content of a message. The message body can contain its own internal structure, which only the sending and receiving applications recognize. The MSMQ-MQSeries Bridge does not interpret this structure in any way.
For detailed information about how the MSMQ-MQSeries Bridge maps and converts properties from Message Queuing to WebSphere MQ and from WebSphere MQ to Message Queuing, see the "Microsoft Host Integration Server 2000 Developer's Guide" on MSDN.
The MSMQ-MQSeries Bridge in HIS 2000 enables you to exchange messages between MSMQ and WebSphere MQ. However, as Chapter 3, "Interoperability Fundamentals," discusses at length, mere message exchange does not guarantee interoperability.
You now know that the MSMQ-MQSeries Bridge does not manipulate the contents of a message as it is passes between the two queuing systems. Hence it is up to you to ensure that messages are in a common format that both the .NET Framework and Java applications understand.
To ensure that messages exchanged through the MSMQ-MQSeries Bridge are in a common format, you need to understand how .NET Framework and Java applications send and receive messages to their respective queues, starting on the .NET Framework side.
When a .NET Framework client sends an object to a MSMQ queue, either a binary or XML formatter serializes the contents of the object. Likewise, when a .NET Framework client receives a message, it expects the message to be serialized in either binary or XML format.
Java handles sending and receiving messages to or from a queue differently from the .NET Framework. A Java client can send messages to a WebSphere MQ queue using either the native WebSphere MQ API or JMS. If the client uses the WebSphere MQ API, the object travels as a simple byte stream rather than in serialized form.
Note JMS also sends the object as a byte stream, but wrapped with additional JMS header information.
Sending Messages from .NET Framework to Java Applications
You can choose whether a .NET Framework client uses a binary or XML serializer when sending messages to MSMQ. However, Chapter 3, "Interoperability Fundamentals," described how the binary serializers in the .NET Framework and Java are incompatible. Therefore, when sending a complex data type object to MSMQ for transferring to WebSphere MQ and a Java client, the .NET Framework client should only use the XML formatter.
The message that the Java client receives from WebSphere MQ consists of a string object containing the serialized XML representation of the original .NET Framework object. Using the techniques described in Chapter 3, "Interoperability Fundamentals," the Java client must then interpret this string as XML, and de-serialize it into a matching object in Java. This process assumes that the data type object that the .NET Framework client side passes derives from the same common XML Schema as the one in Java. It is up to you to de-serialize the received object in the Java client correctly, as described in Chapter 3, "Interoperability Fundamentals."
Sending Messages from Java to .NET Framework Applications
As discussed earlier, messages sent to a WebSphere MQ queue using JMS include additional header information. Unfortunately, the .NET Framework does not understand this information. Therefore, if you want to send messages to a .NET Framework application, your Java client should use the native WebSphere MQ API or, if using JMS, set the target client to MQ.
In addition, because the WebSphere MQ API does not serialize messages that Java clients place into the queue, the Java client needs to serialize the object into XML format before sending it. You can accomplish this using the techniques in Chapter 3, "Interoperability Fundamentals." This ensures that the .NET Framework client can de-serialize the XML formatted message it receives back into an object.
Implementing the MSMQ-MQSeries Bridge
There are several requirements for implementing the MSMQ-MQSeries Bridge. This section provides an overview of these requirements, and the architecture required to set up the bridge.
Note For detailed instructions about setting up and configuring the bridge, consult the HIS 2000 product documentation.
The MSMQ-MQSeries Bridge requires an instance of Microsoft Active Directory to be in place to function properly. This dependency springs from how the MSMQ-MQSeries Bridge works.
From MSMQ to WebSphere MQ, the MSMQ-MQSeries Bridge picks up messages from public queues published in Active Directory. These queues exist in a defined foreign site. The bridge then delivers the messages to a nominated queue on WebSphere MQ.
The reverse path involves the bridge picking up messages from the nominated WebSphere MQ queue and delivering them to a public MSMQ queue. Because you can only define foreign sites and public queues in Active Directory, operation of the bridge requires that you have Active Directory installed and configured.
You install the MSMQ-MQSeries Bridge on a computer running Windows 2000 or Windows Server 2003 that acts as a connection point between the networks. You must install a MSMQ routing server on the same computer as MSMQ-MQSeries Bridge, and this computer must be able to connect by a TCP/IP or LU 6.2 link to an MQSeries Queue Manager.
You must install WebSphere MQ on a Windows server to use the bridge to connect to MSMQ. This could be seen as a complicating factor if your existing WebSphere MQ implementation is on another operating system. One of the reasons for this requirement is to ensure that authentication works by enabling the computer hosting WebSphere MQ to participate in the same Active Directory forest. However, you can work around this issue by setting up a computer running Windows and WebSphere MQ, installing the bridge component, and configuring that computer to link automatically to the queues in your existing non-Windows environment.
In a test environment, you could run the MSMQ-MQSeries Bridge on the same computer as WebSphere MQ. However, this is not recommended in production. The computer running the bridge must either be a member server in an Active Directory domain (production environments) or a domain controller (test environments only).
This chapter first described how you can achieve interoperability by sharing a database between two platforms. It covered the current best practice for accessing data stores, including protecting code against changes. The second part of the chapter covers message-based interoperability mechanisms that provide support for transactions and for long-running operations. It described how you can use message queuing products from either Microsoft or J2EE vendors to make connections to Data tier components hosted either on the .NET Framework or on J2EE. With this knowledge, you can now look at the application architecture of the XBikes Web site and see how the developers applied the techniques in Chapters 4 and 5.
For more information about ResultSets
See the "JDBC Guide: Getting Started"
For more information about using JDBC
See "JDBC Data Access API"
For more information about the Microsoft SQL Server 2000 Driver for JDBC Service Pack 1, including download information
For more information about connecting to SQL Server 2000 with the Microsoft JDBC driver
Microsoft Knowledge Base article Q313100, "HOW TO: Get Started with Microsoft JDBC"
For more information about MSMQ features
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"
For an example of a Web service interface that exposes MSMQ to Java clients
See the section about Creating a Web Service Interface for MSMQ in Microsoft .NET and J2EE Interoperability Toolkit, by Simon Guest, Microsoft Press, ISBN 0-7356-1922-0.
For more information about J-Integra
For details about implementing J-Integra
See "Introducing J-Integra 1.5.5"
http://www.intrinsyc.com/support/j-integra/doc/ [Content link no longer available, original URL:http://www.intrinsyc.com/support/j-integra/doc/]
- and -
"Java Servlet to MSMQ Example"
http://www.intrinsyc.com/support/j-integra/doc/servlet_com/ServletToMsmqExample.html [Content link no longer available, original URL:http://www.intrinsyc.com/support/j-integra/doc/servlet_com/ServletToMsmqExample.html]
For more information about WS-Reliable Messaging
See "Web Services Reliable Messaging Protocol (WS-ReliableMessaging)"
For more information about WS-Transaction
See "Web Services Transaction (WS-Transaction)"
For more information about administering WebSphere MQ
For more information about the JMS standard
See "Java Message Service API"
You can obtain CSD05 at
For more information about HIS
For detailed information about how the MSMQ-MQSeries Bridge maps and converts properties from Message Queuing to WebSphere MQ and from WebSphere MQ to Message Queuing
See the "Microsoft Host Integration Server 2000 Developer's Guide"
For an example of how to use the managed provider for SQL Server to connect to a SQL Server database
See "Connecting to SQL Server Using ADO.NET"
For an example of how to retrieve data from a database using a data reader object
See "Retrieving Data Using the DataReader"
For more information about designing Data Access Logic Components in the .NET Framework
See Chapter 2, "Designing the Components of an Application or Service," of Application Architecture for .NET: Designing Applications and Services
For more information about implementing Data Access Logic Components in .NET Framework
See the .NET Data Access Architecture Guide
For information about implementing the DAO pattern in J2EE
See Core J2EE Patterns Best Practices and Design Strategies by Deepak Alur, Dan Malks, and John Crupi (ISBN 0-13-064884-1).
For an example of calling a Web service asynchronously in the .NET Framework
See "Communicating with XML Web Services Asynchronously"
To install MQSeries Publish/Subscribe support
Download the SupportPac MA0C from the Business Integration Web page on the IBM Web site
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.