The managed MQ subscriber is the preferred pattern for most subscriber applications. The
example requires no administrative definition of queues, topics or subscriptions.
This simplest kind of managed subscriber typically uses a non-durable subscription. The
example focuses on a non-durable subscription. The subscription lasts only as long as the lifetime
of the subscription handle from MQSUB. Any publications that match the topic string
during the lifetime of the subscription are sent to the subscription queue (and possibly a retained
publication if the flag MQSO_NEW_PUBLICATIONS_ONLY is not set or defaulted, an
earlier publication matching the topic string was retained, and the publication was persistent or
the queue manager has not terminated, since the publication was created).
We can also use a durable subscription with this pattern. Typically if a managed durable
subscription is used it is done for reliability reasons, rather than to establish a subscription
that, without any errors occurring, would outlive the subscriber. For more information about
different life cycles associated with managed, unmanaged, durable and non-durable subscriptions see
the related topics section.
Durable subscriptions are often associated with persistent publications, and non-durable subscriptions with non-persistent publications, but there is no necessary relationship between subscription durability and publication persistence. All four combinations of persistence and durability are possible.
For the managed non-durable case considered, the queue manager creates a subscription queue that is purged and deleted when the queue is closed. The publications are removed from the queue when the non-durable subscription is closed.
The valuable facets of the managed non-durable pattern exemplified by this code are as follows:
On demand subscription: the subscription topic string is dynamic. It is provided by the
application when it runs.
Self managing queue: the subscription queue is self defining and managing.
Self managing subscription lifecycle: non-durable subscriptions only exist for the
duration of the subscriber application.
If you define a durable managed subscription, then it results in a permanent subscription
queue and publications continue to be stored on it with no subscriber programs being active. The
queue manager deletes the queue (and clears any unretrieved publications from it) only after the
application or administrator has chosen to delete the subscription. The subscription can be deleted
using an administrative command, or by closing the subscription with the
MQCO_REMOVE_SUB option.
Consider setting SubExpiry for durable subscriptions so that publications cease
to be sent to the queue and the subscriber can consume any remaining publications before removing
the subscription and causing the queue manager to delete the queue and any remaining publications on
it.
Flexible topic string deployment: Subscription topic management is simplified by defining the
root part of the subscription using an administratively defined topic. The root part of the topic
tree is then hidden from the application. By hiding the root part an application can be deployed
without the application inadvertently creating a topic tree that overlaps with another topic tree
created by another instance, or another application.
Administered topics: by using a topic string in which the first part matches an administratively
defined topic object, publications are managed according to the attributes of the topic object.
For example, if the first part of the topic string matches the topic string associated with a
clustered topic object, then the subscription can receive publications from other members of the
cluster
The selective matching of administratively defined topic objects and programmatically defined
subscriptions enables you to combine the benefits of both. The administrator provides attributes for
topics, and the programmer dynamically defines subtopics without being concerned about the
management of topics.
It is the resultant topic string which is used to match the topic object that provides the
attributes associated with the topic, and not necessarily the topic object named in
sd.Objectname, although they typically turn out to be one and the same. See Example 2: Publisher to a variable topic.
By making the subscription durable in the example, publications continue to be sent to the
subscription queue after the subscriber has closed the subscription with the
MQCO_KEEP_SUB option . The queue continues to receive publications when the
subscriber is not active. We can override this behavior by creating the subscription with the
MQSO_PUBLICATIONS_ON_REQUEST option and using MQSUBRQ to request
the retained publication.
The subscription can be resumed later by opening the subscription with the MQCO_RESUME option.
We can use the queue handle, Hobj, returned by MQSUB in a
number of ways. The queue handle is used in the example to inquire on the name of the subscription
queue. Managed queues are opened using the default model queues
SYSTEM.NDURABLE.MODEL.QUEUE or SYSTEM.DURABLE.MODEL.QUEUE. We can
override the defaults by providing your own durable and non-durable model queues on a topic by topic
basis as properties of the topic object associated with the subscription.
Regardless of the attributes inherited from the model queues, we cannot reuse a managed queue
handle to create an additional subscription. Nor can you obtain another handle for the managed queue
by opening the managed queue a second time using the returned queue name. The queue behaves as if it
has been opened for exclusive input .
Unmanaged queues are more flexible than managed queues. We can, for example share unmanaged
queues, or define multiple subscriptions on the one queue. The next example, , demonstrates how to
combine subscriptions with an unmanaged subscription queue.
Note: The compact coding style is intended for readability not production use.
Figure 1. Managed MQ subscriber - part 1: declarations and parameter
handling.
There are some additional comments to make about the declarations in this example.
MQHOBJ Hobj = MQHO_NONE;
We cannot explicitly open a non-durable managed subscription queue to receive publications, but
we do need to allocate storage for the object handle the queue manager returns when it opens the
queue for you. It is important to initialize the handle to MQHO_OBJECT. This
indicates to the queue manager that it needs to return a queue handle to the subscription queue.
Although the example doesn't require knowledge of the subscription queue, the example does
inquire the name of the subscription queue - the MQINQ binding is a little awkward
in the C language, so you might find this part of the example useful to study.
Figure 2. Managed MQ subscriber - part 2: code body.
If topicName is null or blank (default value), the topic name is not used to compute the resolved topic string.
sd.ObjectString.VSPtr = topicString;
Rather than solely use a predefined topic object, in this example the programmer provides a topic object and a topic string, that are combined by MQSUB. Notice the topic string is a MQCHARV structure.
sd.ObjectString.VSLength = MQVS_NULL_TERMINATED;
An alternative to setting the length of a MQCHARV field.
After defining the topic string, the sd.Options flags need the most careful
attention. There are many options, the example specifies only the most commonly used ones. The other
options use the default values.
As the subscription is non-durable, that is, it has a lifetime of the open subscription
in the application, set the MQSO_CREATE flag . We can also set the
(default)
MQSO_NON_DURABLE flag for readability.
Complementing MQSO_CREATE is MQSO_RESUME. Both flags can be
set together; the queue manager either creates a new subscription or resumes an existing
subscription, whichever is appropriate. However, if we do specify MQSO_RESUME you
must also initialize the MQCHARV structure for sd.SubName, even if
there is no subscription to resume. Failure to initialize SubName results in a
return code of 2440: MQRC_SUB_NAME_ERROR from MQSUB. Note:
MQSO_RESUME is always ignored for a non-durable managed subscription: but
specifying it without initializing the MQCHARV structure for
sd.SubName does cause the error.
In addition there is a third flag affecting how the subscription is opened,
MQSO_ALTER. Given the correct permissions, the properties of a resumed subscription
are changed to match other attributes specified in MQSUB. Note: At least one of the
MQSO_CREATE, MQSO_RESUME and MQSO_ALTER flags
must be specified. See Options
(MQLONG). There are examples of using all three flags in Example 3: Unmanaged MQ subscriber.
Set MQSO_MANAGED for the queue manager to manage the subscription for you
automatically.
sd.ObjectString.VSLength = MQVS_NULL_TERMINATED;
Optionally, omit setting the length of MQCHARV for null terminated strings and use the null terminator flag instead.
sd.ResObjectString.VSPtr = resTopicStr;
The resulting topic string is echoed in first printf in the program. Set up MQCHARV ResObjectString for IBM MQ to return the resolved string back to the program.
Note: resTopicStringBuffer is initialized to nulls in memset(resTopicStr, 0, sizeof(resTopicStrBuffer)). Returned topic strings do not end with a trailing null.
Set the buffer size of the sd.ResObjectString to one less than its actual size.
This prevents overwriting the null terminator that is provided, in case the resolved topic string
fills the entire buffer. Note: No error is returned if the topic string is longer than
sizeof(resTopicStrBuffer)-1. Even if VSLength > VSBufSiz the
length returned in sd.ResObjectString.VSLength is the length of the complete string
and not necessarily the length of the returned string. Test sd.ResObjectString.VSLength <
sd.ResObjectString.VSBufSiz to confirm the topic string is complete.
The MQSUB function creates a subscription. If it is non-durable you are
probably not interested in its name, though we can inspect its status in IBM MQ Explorer. We can provide the sd.SubName
parameter as input, so you know what name to look for; you obviously have to
avoid name clashes with other subscriptions.
Closing both the subscription and the subscription queue is optional. In the example the subscription is closed, but not the queue. The MQCLOSE MQCO_REMOVE_SUB option is the default in this case anyway as the subscription is non-durable. Using MQCO_KEEP_SUB is an error.
Note: the subscription queue is not closed by MQSUB, and its handle, Hobj, remains valid until the queue is closed by MQCLOSE or MQDISC. If the application terminates prematurely, the queue and subscription are cleaned up by the queue manager sometime after application termination.