Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

A C++ Library for IBM MQSeries


Jul00: A C++ Library for IBM MQSeries

Jack, a DDJ contributing editor, can be contacted at [email protected].


IBM MQSeries is a distributed messaging system that has been ported to many platforms, from mainframe operating systems such as OS/390 and VM/ESA to UNIX servers such as AIX, Solaris, HP, Linux, as well as to OS/2, Windows NT, and Windows 3.1. MQSeries adds what might be called a "Windows-like message loop" to distributed environments. While many means of synchronous and asynchronous interprocess- and interplatform communication exist, most of them are established by negotiation between each of the messaging partners. In MQSeries, there is a third party involved -- the message queue server -- that may reside on the same machine as any of the messaging partners, but is conceptually a discrete entity that is administered separately from messaging clients.

MQSeries is a simple but powerful application of network theory. Clients open queues on the server for putting messages, getting messages, or both. All messages are put to and fetched from the queue, indirectly between applications.

Administrative actions establish one or more message queues for the set of distributed programs that will employ MQSeries. Configuration includes maximum message size, permission attributes, security exits, and so on. There are no limits beyond the practical to the number of queues, the number of network hops between multiple queue servers, or the number of clients that may participate in exchanging messages in any practical topology.

MQSeries administration empowers application design. Client programs have an efficient, reliable, characterizable means of asynchronous data exchange. Clients awaiting messages can poll the queue or block for a message. Because MQSeries administration is centralized in the intermediate layer (the message queue server), there is less of an application design question as to whether a given client program's periodic response will be sufficient to prevent overflow of some application-specific queuing resource. The limitations, such as there are, are centralized on the capacity of the message queue server as configured. Furthermore, persistence of data residing in the queue means interrupted service can be resumed without loss of transactions.

Uses of MQSeries in the real world range from transaction systems that span legacy platforms and modern desktops to applications that might have been tempted toward CORBA but find MQSeries vastly simpler in instances where the crux of the application is continual data flow between stages running in multiple process spaces (typically on separate and dissimilar hardware platforms). An exotic use of MQSeries under development is a stock trader's "heads-up" compute-anywhere system, allowing the ticker tape to roll by projected on the trader's retina while he's shouting up from the floor.

Early versions of MQSeries sported a standard C programming interface. In recent releases, IBM has started to provide its own C++ bindings. When working on a large ordering system where my station was one of the many destinations of a large data flow, I developed the "SoftWoehr library" -- the open-source C++ class library presented here. SoftWoehr also encapsulates the C language bindings exposed by MQSeries, but is a good deal simpler than IBM's. Still, SoftWoehr is standard C++ and should compile on any MQSeries-supported platform if you have a standard C++ compiler that supports the Standard C++ Libraries. The SoftWoehr library also has a different linguistic flavor than the IBM libraries, a flavor that some C++ programmers might find congenial.

The first step in MQSeries messaging the SoftWoehr library is to open an extant message queue manager. Creating a message queue manager is an administrative task generally performed through scripting or at the command line. Let's say you want to open a queue manager named MYQMGR. Using SoftWoehr, you open this manager using Listing One.

The next step is to open some queue managed by the manager. Let's say the queue is called APRICOT.QUEUE, so your code would read like Listing Two. Note that the queue was opened for both shared input and output. This call might fail due to a prior exclusive open, so you need to catch exceptions and see what any problem might be. Of course, the application itself may be programmed to recover or modify its behavior based on the MQSeries low-level completion code and reason code for failures that are carried along in the exception and for which specific accessors are provided.

Next, you might wish to put a message to the queue. The library treats all messages as an array of unsigned char. The library does not care about the message contents. Because there are some specific formats supported in MQSeries, later versions of the SoftWoehr library will include some specific support for these formats. Listing Three, for instance, just sends some silly text. Another application that has already opened the queue manager and queue for reading might then fetch the message back using Listing Four.

The SoftWoehr class library for IBM MQSeries is available from DDJ (see "Resource Center," page 5) as well as IBM's MQSeries SupportPac page (http://www .ibm.com/software/ts/mqseries/txppacs/ txpsumm.html) as a Category 4 (third-party contribution), and from the SoftWoehr Home Page (http://www.well .com/user/ jax/SoftWoehr).

DDJ

Listing One

#include "jaxmq.hpp"
using namespace SoftWoehr;
// ...
   /* A queue mgr to work with */
   MQQueueManager mq_queue_manager;
      /* Connect to our queue manager */
      try {
         mq_queue_manager.connect("MYQMGR");
         }
      /* Failed to open queue manager. */
      catch (MQQueueManager::FailedToConnectException & ex) {
         cout << "MQQueueManager::FailedToConnectException caught "
              << "opening " << queue_manager_name
              <<" ... Info follows:" << endl;
         cout << ex.get_text() << endl;
         cout << "Completion code : " << ex.get_completion_code() << endl;
         cout << "Reason          : " << ex.get_reason()          << endl;
         }
      /* Failed to open queue manager. */
      catch (MQException & ex) {
         cout << "MQQueueManager::MQException caught "
              << "opening " << queue_manager_name
              <<" ... Info follows:" << endl;
         cout << ex.get_text() << endl;
         }
      /* Announce success */
      cout << "MQQueueManager "
           << mq_queue_manager.get_name()
           << " called MQCONN()."  << endl;
      cout << "Handle is now      : "
           << mq_queue_manager.get_connection_handle()  << endl;
      cout << "Completion code is : "
           << mq_queue_manager.get_completion_code()    << endl;
      cout << "Reason is          : "
           << mq_queue_manager.get_reason()             << endl;

Back to Article

Listing Two

/* Open a queue */
try {
   MQObject::Options options ( MQObject::Options::open_input_shared
                             | MQObject::Options::open_output
                             )
                             ;
   mq_queue.open( mq_queue_manager
                , "APRICOT.QUEUE"
                , options
                )
                ;
   }

catch (MQQueue::FailedToOpenException & ex) {
   cout << "MQQueue::FailedToOpenException caught "
        << "opening APRICOT.QUEUE"
        << " ... Info follows:" << endl;
   cout << ex.get_text() << endl;
   }
catch (MQException &ey) {
   cout << "MQException caught "
        << "opening APRICOT.QUEUE"e
        << " ... Info follows:" << endl;
   cout << ey.get_text() << endl;
   }

Back to Article

Listing Three

 /* A message to put */
#define SILLY_MSG "This is the way we wash our queues!"
    MQMessage mq_message;
    mq_message.set_message(SILLY_MSG, strlen(SILLY_MSG) +1);
    try {
       /** Put a message */
       mq_queue.put(mq_message);
       }
    catch (MQObject::NotOpenedException & noex)
      {
      cout << "Exception caught putting message: " << noex.get_text() << endl;
      }
    catch (MQQueue::MessagePutException & mpex)
      {
      cout << "Exception caught putting message: " << mpex.get_text() << endl;
      cout << "Condition code: " << mpex.get_completion_code() << endl;
      cout << "Reason: "         << mpex.get_reason() << endl;
      }

Back to Article

Listing Four

/* Empty message to receive incoming. */
MQMessage mq_get_message;
try {
   /* The MQMessage can hold any practical length. Here's it just 
    * arbitrarily 1000 bytes max for our silly message.
    */
   mq_queue.get(mq_get_message, 1000);
   }
catch (MQObject::NotOpenedException & nonoex)
   {
   cout << "Exception caught getting message: " << nonoex.get_text() << endl;
   }
catch (MQQueue::MessageGetException & mgex)
   {
   cout << "Exception caught getting message: " << mgex.get_text() << endl;
   cout << "Condition code: " << mgex.get_completion_code() << endl;
   cout << "Reason: "         << mgex.get_reason() << endl;
   }
/* Print out the returned message */
cout << "Returned message == '"
     << mq_get_message.get_message()
     <<"'"
     << endl;

Back to Article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.